PluginProbe
wpForo Forum / 3.0.9
wpForo Forum v3.0.9
3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 All 137 releases
wpforo / classes / Phrases.php

Phrases.php in wpForo Forum 3.0.9, at classes/Phrases.php

437 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace wpforo\classes;
4
5 use wpforo\admin\listtables\Phrases as PhrasesListTable;
6
7 // Exit if accessed directly
8 if( ! defined( 'ABSPATH' ) ) exit;
9
10 class Phrases {
11 public $phrases;
12 public $__phrases;
13 public $list_table;
14 public $langid;
15
16 public function __construct() {
17 add_action( 'wpforo_after_change_board', function() {
18 $this->init();
19 } );
20 }
21
22 private function init() {
23 if( WPF()->is_installed() ) {
24 $this->langid = $this->get_current_langid();
25 if( is_admin() ) $this->init_list_table();
26 if( $phrases = $this->get_phrases() ) {
27 foreach( $phrases as $phrase ) {
28 $this->phrases[ addslashes( strtolower( (string) $phrase['phrase_key'] ) ) ] = $phrase['phrase_value'];
29 $this->__phrases[ addslashes( strtolower( (string) $phrase['phrase_key'] ) ) ] = wpforo_phrase( $phrase['phrase_key'], false );
30 }
31 add_action( 'wp_ajax_nopriv_wpforo_get_phrases', [ $this, 'ajax_get_phrases' ] );
32 add_action( 'wp_ajax_wpforo_get_phrases', [ $this, 'ajax_get_phrases' ] );
33 }
34 }
35 }
36
37 public function init_list_table() {
38 if( wpfval( $_GET, 'page' ) === wpforo_prefix_slug( 'phrases' ) ) {
39 $this->list_table = new PhrasesListTable();
40 $this->list_table->prepare_items();
41 }
42 }
43
44 function add( $args = [], $clear_cache = true ) {
45 if( empty( $args ) && empty( $_REQUEST['phrase'] ) ) return false;
46 if( empty( $args ) && ! empty( $_REQUEST['phrase'] ) ) $args = $_REQUEST['phrase'];
47
48 if( empty( $args['langid'] ) ) $args['langid'] = $this->langid;
49 if( empty( $args['package'] ) ) $args['package'] = 'wpforo';
50 $sql = WPF()->db->prepare(
51 "INSERT IGNORE INTO `" . WPF()->tables->phrases . "`
52 (`langid`, `phrase_key`, `phrase_value`, `package`)
53 VALUES (%d, %s, %s, %s)",
54 intval( $args['langid'] ),
55 sanitize_text_field( stripslashes( (string) $args['key'] ) ),
56 sanitize_text_field( stripslashes( (string) $args['value'] ) ),
57 stripslashes( (string) $args['package'] )
58 );
59 if( false !== WPF()->db->query( $sql ) ) {
60 $phraseid = WPF()->db->insert_id;
61 WPF()->notice->add( 'Phrase successfully added', 'success' );
62 if( $clear_cache ) $this->clear_cache();
63
64 return $phraseid;
65 }
66 WPF()->notice->add( 'Phrase add error', 'error' );
67
68 return false;
69 }
70
71 function edit( $args = [] ) {
72 if( ! $args && ! empty( $_REQUEST['phrases'] ) ) $args = $_REQUEST['phrases'];
73 if( ! empty( $args ) ) {
74 foreach( $args as $phraseid => $phrase ) {
75 WPF()->db->update(
76 WPF()->tables->phrases,
77 [ 'phrase_value' => sanitize_text_field( stripslashes( (string) $phrase ) ) ],
78 [ 'phraseid' => intval( $phraseid ) ],
79 [ '%s' ],
80 [ '%d' ]
81 );
82 }
83 $this->clear_cache();
84 WPF()->notice->add( 'Phrase successfully updates', 'success' );
85
86 return true;
87 }
88
89 WPF()->notice->add( 'Phrase update error', 'error' );
90
91 return false;
92 }
93
94 function get_phrase( $phraseid ) {
95 $sql = 'SELECT * FROM ' . WPF()->tables->phrases . ' WHERE `phraseid` =' . intval( $phraseid );
96
97 return WPF()->db->get_row( $sql, ARRAY_A );
98 }
99
100 function get_phrases( $args = [], &$items_count = 0, $count = false ) {
101 $default = [
102 'include' => [], // array( 2, 10, 25 )
103 'exclude' => [], // array( 2, 10, 25 )
104 'langid' => $this->langid,
105 'package' => [],
106
107 'orderby' => 'phraseid',
108 'order' => 'ASC', // ASC DESC
109 'offset' => '', // this use when you give row_count
110 'row_count' => '',
111 ];
112
113 $args = wpforo_parse_args( $args, $default );
114
115 $key = WPF()->tables->phrases . substr( md5( serialize( $args ) ), 0, 10 );
116
117 // Security: extract only expected keys instead of extract()
118 $include = $args['include'];
119 $exclude = $args['exclude'];
120 $langid = $args['langid'];
121 $package = $args['package'];
122 $orderby = $args['orderby'];
123 $order = $args['order'];
124 $offset = $args['offset'];
125 $row_count = $args['row_count'];
126
127 $package = wpforo_parse_args( $package );
128 $include = wpforo_parse_args( $include );
129 $exclude = wpforo_parse_args( $exclude );
130
131 $wheres = [];
132
133 if( ! empty( $package ) ) $wheres[] = "`package` IN('" . implode( "','", array_map( 'esc_sql', array_map( 'sanitize_text_field', $package ) ) ) . "')";
134 if( ! empty( $include ) ) $wheres[] = "`phraseid` IN(" . implode( ', ', array_map( 'intval', $include ) ) . ")";
135 if( ! empty( $exclude ) ) $wheres[] = "`phraseid` NOT IN(" . implode( ', ', array_map( 'intval', $exclude ) ) . ")";
136 if( ! is_null( $langid ) ) $wheres[] = "`langid` = " . intval( $langid );
137
138 $sql = "SELECT * FROM `" . WPF()->tables->phrases . "`";
139 if( ! empty( $wheres ) ) {
140 $sql .= " WHERE " . implode( " AND ", $wheres );
141 }
142
143 if( $count ) {
144 $item_count_sql = preg_replace( '#SELECT.+?FROM#isu', 'SELECT count(*) FROM', $sql );
145 if( $item_count_sql ) $items_count = WPF()->db->get_var( $item_count_sql );
146 }
147
148 $sql .= esc_sql( " ORDER BY `$orderby` " . $order );
149
150 if( $row_count != '' && $offset == '' ) { // If you give only row_count this if fixed problam
151 $offset = $row_count;
152 $row_count = '';
153 }
154 $sql .= $offset != '' ? esc_sql( ' LIMIT ' . $offset ) : '';
155 $sql .= $row_count != '' ? esc_sql( ', ' . $row_count ) : '';
156
157 if( false === ( $phrases = get_transient( 'wpforo_get_phrases_' . $key ) ) ) {
158 $phrases = WPF()->db->get_results( $sql, ARRAY_A );
159 set_transient( 'wpforo_get_phrases_' . $key, $phrases, 60 * 60 * 24 );
160 }
161
162 return get_transient( 'wpforo_get_phrases_' . $key );
163 }
164
165 function search( $needle = '', $fields = [ 'phrase_key', 'phrase_value' ] ) {
166 $fields = (array) $fields;
167 if( ! $needle || empty( $fields ) ) return [];
168
169 $needle = substr( sanitize_text_field( (string) $needle ), 0, 60 );
170 $sql = "SELECT `phraseid` FROM " . WPF()->tables->phrases;
171 $wheres = [];
172 foreach( $fields as $field ) {
173 $field = sanitize_text_field( $field );
174 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $needle ) . "%'";
175 }
176 if( $wheres ) $sql .= ' WHERE ' . implode( ' OR ', $wheres );
177
178 return WPF()->db->get_col( $sql );
179 }
180
181 public function xml_import( $xmlfile ) {
182 $file = WPFORO_DIR . '/admin/assets/xml/' . $xmlfile;
183 if( file_exists( $file ) && function_exists( 'xml_parser_create' ) ) {
184 $xr = xml_parser_create();
185 $fp = fopen( $file, "r" );
186 $xml = fread( $fp, filesize( $file ) );
187
188 xml_parser_set_option( $xr, XML_OPTION_CASE_FOLDING, 1 );
189 xml_parse_into_struct( $xr, $xml, $vals );
190 if( PHP_VERSION_ID < 80000 ) {
191 xml_parser_free( $xr );
192 }
193
194 delete_transient( 'wpforo_get_phrases' );
195
196 if( ! empty( $vals ) && isset( $vals[0]['tag'] ) && $vals[0]['tag'] == 'LANGUAGE' && isset( $vals[0]['attributes']['LANGUAGE'] ) && $vals[0]['attributes']['LANGUAGE'] ) {
197
198 $sql = "SELECT `langid` FROM `" . WPF()->tables->languages . "` WHERE `name` LIKE '" . esc_sql( sanitize_text_field( $vals[0]['attributes']['LANGUAGE'] ) ) . "'";
199 $langid = WPF()->db->get_var( $sql );
200
201 if( ! $langid ) {
202 $sql = "INSERT INTO `" . WPF()->tables->languages . "` (`name`) VALUES ( '" . esc_sql( sanitize_text_field( $vals[0]['attributes']['LANGUAGE'] ) ) . "' )";
203 if( WPF()->db->query( $sql ) ) {
204 $langid = WPF()->db->insert_id;
205 $this->set_language_status( $langid );
206 }
207 }
208
209 if( $langid ) {
210 foreach( $vals as $val ) {
211 if( isset( $val['tag'] ) && $val['tag'] == 'PHRASE' && isset( $val['attributes']['NAME'] ) && trim( (string) $val['attributes']['NAME'] ) && isset( $val['value'] ) && trim(
212 (string) $val['value']
213 ) ) {
214 $sql = "INSERT IGNORE INTO `" . WPF()->tables->phrases . "`
215 (`phraseid`, `langid`, `phrase_key`, `phrase_value`)
216 VALUES( NULL,
217 '" . intval( $langid ) . "',
218 '" . esc_sql( stripslashes( htmlspecialchars_decode( (string) $val['attributes']['NAME'], ENT_QUOTES ) ) ) . "',
219 '" . esc_sql( stripslashes( htmlspecialchars_decode( (string) $val['value'], ENT_QUOTES ) ) ) . "')";
220 WPF()->db->query( $sql );
221 }
222 }
223
224 return $langid;
225 }
226 }
227 }
228
229 return false;
230 }
231
232 function add_lang() {
233 if( is_array( $_FILES['add_lang']['name'] ) && ! empty( $_FILES['add_lang']['name'] ) && isset( $_FILES['add_lang']['name']['xml'] ) ) {
234 if( ! is_dir( WPFORO_DIR . '/admin/xml' ) ) wp_mkdir_p( WPFORO_DIR . '/admin/xml' );
235
236 $error = $_FILES['add_lang']['error']['xml'];
237
238 if( $error ) {
239 $error = wpforo_file_upload_error( $error );
240 WPF()->notice->add( $error, 'error' );
241
242 return false;
243 }
244
245 $xmlfile = strtolower( sanitize_file_name( $_FILES['add_lang']['name']['xml'] ) );
246 $ext = strtolower( (string) pathinfo( $xmlfile, PATHINFO_EXTENSION ) );
247 if( $ext === 'xml' ) {
248 if( move_uploaded_file( sanitize_text_field( $_FILES['add_lang']['tmp_name']['xml'] ), WPFORO_DIR . '/admin/assets/xml/' . $xmlfile ) ) {
249 if( $langid = $this->xml_import( $xmlfile ) ) {
250 delete_transient( 'wpforo_get_phrases' );
251 WPF()->notice->add( 'New language successfully added and changed wpforo language to new language', 'success' );
252
253 return $langid;
254 }
255 }
256 } else {
257 WPF()->notice->add( 'Incorrect file type', 'error' );
258
259 return false;
260 }
261 }
262
263 WPF()->notice->add( 'Can\'t add new language', 'error' );
264
265 return false;
266 }
267
268 public function set_language_status( $langid ) {
269 if( WPF()->db->update(
270 WPF()->tables->languages,
271 [ 'status' => 1 ],
272 [ 'langid' => $langid ],
273 [ '%d' ],
274 [ '%d' ]
275 ) ) {
276 return false !== WPF()->db->query(
277 WPF()->db->prepare(
278 "UPDATE `" . WPF()->tables->languages . "` SET `status` = 0 WHERE `langid` <> %d",
279 $langid
280 )
281 );
282 }
283
284 return false;
285 }
286
287 public function get_current_langid() {
288 $langid = (int) WPF()->db->get_var(
289 "SELECT `langid` FROM `" . WPF()->tables->languages . "` WHERE `status` = 1 ORDER BY `langid` DESC"
290 );
291 if( ! $langid ) {
292 $langid = (int) WPF()->db->get_var(
293 "SELECT `langid` FROM `" . WPF()->tables->languages . "` ORDER BY `langid` DESC"
294 );
295 }
296
297 return $langid;
298 }
299
300 public function get_language( $langid ) {
301 return WPF()->db->get_row(
302 WPF()->db->prepare(
303 "SELECT * FROM `" . WPF()->tables->languages . "` WHERE `langid` = %d",
304 $langid
305 ),
306 ARRAY_A
307 );
308 }
309
310 function get_languages() {
311 return WPF()->db->get_results( "SELECT * FROM `" . WPF()->tables->languages . "`", ARRAY_A );
312 }
313
314 function show_lang_list( $selected = null ) {
315 if( $langs = $this->get_languages() ) {
316 if( ! $selected ) $selected = $this->langid;
317 $selected = intval( $selected );
318 foreach( $langs as $lang ) {
319 $lang['langid'] = intval( $lang['langid'] );
320 printf(
321 '<option value="%1$d" %2$s>%3$s</option>',
322 $lang['langid'],
323 ( $lang['langid'] === $selected ) ? 'selected' : '',
324 esc_html( $lang['name'] )
325 );
326 }
327 }
328 }
329
330 public function get_distinct_packages() {
331 $sql = "SELECT DISTINCT `package` as packages FROM `" . WPF()->tables->phrases . "`";
332
333 return WPF()->db->get_col( $sql );
334 }
335
336 function clear_cache() {
337 WPF()->db->query( "DELETE FROM " . WPF()->db->options . " WHERE `option_name` LIKE '%_wpforo_get_phrases_%'" );
338 }
339
340 public function crawl_phrases( $pattern = null ) {
341 if( is_null( $pattern ) ) $pattern = dirname( WPFORO_DIR ) . DIRECTORY_SEPARATOR . 'wpforo*';
342 if( $matches = glob( $pattern ) ) {
343 $package = 'wpforo';
344 if( preg_match( '#[/\\\]wp-content[/\\\]plugins[/\\\]([^/\\\]+)[/\\\]#isu', (string) $pattern, $p ) ) {
345 $package = $p[1];
346 }
347 foreach( $matches as $match ) {
348 if( is_dir( $match ) ) {
349 $this->crawl_phrases( $match . DIRECTORY_SEPARATOR . '*' );
350 } elseif( is_file( $match ) && preg_match( '#\.(php|js)$#iu', (string) $match ) ) {
351 if( $file_content = wpforo_get_file_content( $match ) ) {
352 if( preg_match_all(
353 '#(?:wpforo_phrase|WPF\(\)->notice->add|wpforo_notice_show|wpforo_load_show)\([\r\n\t\s\0]*[\'\"](?P<phrase_key>.+?)[\'\"][\r\n\t\s\0,)]+#isu',
354 $file_content,
355 $phrases,
356 PREG_SET_ORDER
357 ) ) {
358 foreach( $phrases as $phrase ) {
359 if( $phrase['phrase_key'] ) {
360 $args = [
361 'key' => $phrase['phrase_key'],
362 'value' => __( $phrase['phrase_key'], $package ),
363 'package' => $package,
364 ];
365 $this->add( $args, false );
366 }
367 }
368 }
369 }
370 }
371
372 }
373 }
374 }
375
376 public function rebuild_file_wpf_phrases_php() {
377 $file_path = wpforo_fix_dir_sep( WPFORO_DIR . '/includes/phrases.php' );
378 if( WPF()->is_installed() && $file_content = wpforo_get_file_content( $file_path ) ) {
379
380 if( $phrases = $this->get_phrases( [ 'package' => 'wpforo' ] ) ) {
381 foreach( $phrases as $phrase ) {
382 $key = addcslashes( $phrase['phrase_key'], '"' );
383
384 if( ! preg_match(
385 '#[\'\"]' . preg_quote( $key ) . '[\'\"][\r\n\t\s\0]*=>[\r\n\t\s\0]*__\([\r\n\t\s\0]*[\'\"]' . preg_quote(
386 $key
387 ) . '[\'\"][\r\n\t\s\0]*,[\r\n\t\s\0]*[\'\"]wpforo[\'\"][\r\n\t\s\0]*\)#isu',
388 (string) $file_content
389 ) ) {
390 $file_content = preg_replace(
391 '#(\$wpforo_phrases[\r\n\t\s\0]*=[\r\n\t\s\0]*array\([\r\n\t\s\0]*)#iu',
392 '$1"' . $key . '" => __("' . $key . '", "wpforo"),' . "\r\n\t",
393 (string) $file_content
394 );
395 }
396 }
397
398 wpforo_write_file( $file_path, $file_content );
399 }
400
401 }
402 }
403
404 public function rebuild_file_english_xml() {
405 $file_path = wpforo_fix_dir_sep( WPFORO_DIR . '/admin/assets/xml/english.xml' );
406 if( WPF()->is_installed() && $file_content = wpforo_get_file_content( $file_path ) ) {
407
408 if( $phrases = $this->get_phrases( [ 'package' => 'wpforo' ] ) ) {
409 foreach( $phrases as $phrase ) {
410 $key = htmlspecialchars( $phrase['phrase_key'], ENT_QUOTES );
411
412 if( ! preg_match(
413 '#<phrase[^<>]*?name=[\'\"]' . preg_quote( $key ) . '[\'\"][^<>]*?>[^<>]*?<\!\[CDATA\[' . preg_quote( $key ) . '\]\]>[^<>]*?</phrase>#isu',
414 (string) $file_content
415 ) ) {
416 $file_content = preg_replace( '#([\r\n\t\s\0]*</language>)#iu', "\r\n\t" . '<phrase name="' . $key . '"><![CDATA[' . $key . ']]></phrase>$1', (string) $file_content );
417 }
418 }
419
420 wpforo_write_file( $file_path, $file_content );
421 }
422
423 }
424 }
425
426 public function ajax_get_phrases() {
427 wpforo_verify_nonce( 'wpforo_get_phrases' );
428 echo wp_json_encode( $this->__phrases );
429 exit();
430 }
431
432 public function get_wpforo_phrases_inline_js() {
433 return 'window.wpforo_phrases = ' . wp_json_encode( $this->__phrases ) . ';';
434 }
435
436 }
437