/ json-test.php
json-test.php
  1  <?php
  2  /**
  3   * JSON Dumper
  4   * Dumps a thread into a .json file.
  5   */
  6  
  7  if( !isset( $in_imgboard ) ) die( 'No direct access' );
  8  
  9  if( META_BOARD ) {
 10  	include_once 'plugins/enhance_q.php';
 11  }
 12  
 13  function generate_thread_json( $threadid, $return = false, $replies = false, $for_catalogue = false, $tail = 0 )
 14  {
 15  	global $log, $thread_unique_ips;
 16  	if( !$log[$threadid] ) log_cache( 0, $threadid );
 17  	$carr = array();
 18  
 19  	$op = $log[$threadid];
 20  	foreach( $op['children'] as $key => $val ) {
 21  		$carr[] = $key;
 22  	}
 23  
 24  	sort( $carr, SORT_NATURAL );
 25  
 26  	$count      = count( $carr ) + 1;
 27  	$replycount = $op['replycount'];
 28  
 29  	$build      = '';
 30  	$json       = array();
 31  	$extra      = array();
 32  	$imagecount = $op['imgreplycount'];
 33  	$tail_images = 0;
 34    
 35    $extra['replies'] = $replycount;
 36    $extra['images']  = $imagecount;
 37    
 38    // Not inside a thread
 39    if ($replies !== false) {
 40      if ($replycount - $replies > 0) {
 41        for ($i = $replycount - $replies; $i < $replycount; $i++) {
 42          if ($log[$carr[$i]]['fsize'] && !$log[$carr[$i]]['filedeleted']) {
 43            $tail_images++;
 44          }
 45        }
 46        
 47        $extra['omitted_posts']  = $replycount - $replies;
 48        $extra['omitted_images'] = $imagecount - $tail_images;
 49      }
 50    }
 51    // Inside a thread
 52    else if (SHOW_THREAD_UNIQUES) {
 53      if ($thread_unique_ips) {
 54        $unique_ips = (int)$thread_unique_ips;
 55      }
 56      else {
 57        $unique_ips = get_unique_ip_count($threadid);
 58      }
 59      
 60      if ($unique_ips) {
 61        $extra['unique_ips'] = $unique_ips;
 62      }
 63    }
 64    
 65  	//if( $replycount >= MAX_RES && !$op['permaage'] ) $extra['bumplimit'] = 1;
 66  	//if( $imagecount >= MAX_IMGRES && !$op['sticky'] ) $extra['imagelimit'] = 1;
 67    
 68  	$i = 1;
 69    
 70    if ($op['semantic_url'] !== '') {
 71      $extra['semantic_url'] = $op['semantic_url'];
 72    }
 73    
 74  	if ($replies !== false) {
 75  	  $i = $count - $replies;
 76  	  
 77  	  if ($i < 1) {
 78  	    $i = 1;
 79  	  }
 80    }
 81  
 82    if ($for_catalogue) {
 83      $json = generate_post_json( $op, $threadid, $extra ); // we do op before replies
 84      if ($replycount > 0) {
 85        $json['last_replies'] = array();
 86      	for( ; $i < $count; $i++ ) {
 87      		if( isset( $log[$carr[$i - 1]] ) ) {
 88      			$var    = $log[$carr[$i - 1]];
 89      			$json['last_replies'][] = generate_post_json( $var, $threadid );
 90      		}
 91      	}
 92  			if (META_BOARD) {
 93  				$capcode_replies = generate_capcode_replies($op['children']);
 94  				
 95  				if ($capcode_replies) {
 96  					$json['capcode_replies'] = $capcode_replies;
 97  				}
 98  			}
 99  		}
100  		
101  		$json['last_modified'] = (int)$log[$threadid]['last_modified'];
102  		
103      return $json;
104    }
105    else if ($tail) {
106      $json[] = generate_op_tail_json($op, $extra);
107      
108      $lim = $count - $tail;
109      
110      $tail_id = 0;
111      
112      for (; $i < $count; $i++ ) {
113        if (isset($log[$carr[$i - 1]])) {
114          $var = $log[$carr[$i - 1]];
115          if ($i < $lim) {
116            $tail_id = (int)$var['no'];
117          }
118          else {
119            $json[] = generate_post_json($var, $threadid);
120          }
121        }
122      }
123      
124      $json[0]['tail_size'] = $tail;
125      $json[0]['tail_id'] = $tail_id;
126      
127      $temp = array('posts' => $json);
128    }
129    else {
130      $json[] = generate_post_json( $op, $threadid, $extra ); // we do op before replies
131      
132      $tailSize = get_json_tail_size($threadid);
133      
134      if ($tailSize) {
135        $json[0]['tail_size'] = $tailSize;
136      }
137      
138  		for( ; $i < $count; $i++ ) {
139  			if( isset( $log[$carr[$i - 1]] ) ) {
140  				$var    = $log[$carr[$i - 1]];
141  				$json[] = generate_post_json( $var, $threadid );
142  			}
143    	}
144    	
145  		if (META_BOARD) {
146  			$capcode_replies = generate_capcode_replies($op['children']);
147  			
148  			if ($capcode_replies) {
149  				$json[0]['capcode_replies'] = $capcode_replies;
150  			}
151  		}
152  		
153      $temp = array('posts' => $json);
154    }
155    
156  	if( $return ) return $temp;
157  
158  	unset( $json );
159    
160    if (!$tail) {
161      $filename = RES_DIR . $threadid . '.json';
162    }
163    else {
164      $filename = RES_DIR . $threadid . '-tail.json';
165    }
166  	$page = json_encode($temp);
167  	print_page( $filename, $page, 0, 0 );
168  
169  	return true;
170  }
171  
172  function generate_capcode_replies($replies) {
173  	global $log;
174  	
175  	$capcode_replies = array(
176  		'admin' => array(),
177  		'developer' => array(),
178  		'mod' => array()
179  	);
180  	
181  	$has_capcode_replies = false;
182  	
183  	foreach ($replies as $no => $val) {
184  		if (!isset($log[$no])) {
185  			continue;
186  		}
187  		$json_post = $log[$no];
188  		if ($json_post['capcode'] === 'none') {
189  			continue;
190  		}
191  		if ($json_post['capcode'] === 'admin_highlight') {
192  			$json_capcode = 'admin';
193  		}
194  		else {
195  			$json_capcode = $json_post['capcode'];
196  		}
197  		$capcode_replies[$json_capcode][] = (int)$no;
198  		$has_capcode_replies = true;
199  	}
200  	
201  	if ($has_capcode_replies) {
202  		$ret = array();
203  		foreach ($capcode_replies as $key => $value) {
204  			if (empty($value)) {
205  				continue;
206  			}
207  			$ret[$key] = $value;
208  		}
209  		return $ret;
210  	}
211  	else {
212  		return null;
213  	}
214  }
215  
216  function post_json_force_type( &$post )
217  {
218  	static $post_intern = array(
219  		'no'             => 'integer',
220  		'resto'          => 'integer',
221  		'sticky'         => 'integer',
222  		'closed'         => 'integer',
223  		'archived'       => 'integer',
224  		'now'            => 'string',
225  		'time'           => 'integer',
226  		'name'           => 'string',
227  		'trip'           => 'string',
228  		'id'             => 'string',
229  		'capcode'        => 'string',
230  		'country'        => 'string',
231  		'country_name'   => 'string',
232  		'sub'            => 'string',
233  		'com'            => 'string',
234  		'tim'            => 'integer',
235  		'filename'       => 'string',
236  		'ext'            => 'string',
237  		'fsize'          => 'integer',
238  		'md5'            => 'string',
239  		'w'              => 'integer',
240  		'h'              => 'integer',
241  		'tn_w'           => 'integer',
242  		'tn_h'           => 'integer',
243  		'filedeleted'    => 'integer',
244  		'spoiler'        => 'integer',
245  		'custom_spoiler' => 'integer',
246  		'omitted_posts'  => 'integer',
247  		'omitted_images' => 'integer',
248  		'replies'        => 'integer',
249  		'images'         => 'integer',
250  		'bumplimit'      => 'integer',
251  		'imagelimit'     => 'integer',
252  		'last_modified'  => 'integer',
253  		'archived_on'    => 'integer',
254  		'since4pass'     => 'integer',
255  		'm_img'          => 'integer'
256  	);
257  
258  
259  	foreach( $post as $key => $val) {
260  		if( isset( $post_intern[$key] ) ) {
261  			settype( $post[$key], $post_intern[$key] );
262  		}
263  	}
264  }
265  
266  function generate_op_tail_json($op, $extra) {
267    $ary = array();
268    
269    $ary['no'] = (int)$op['no'];
270    
271    $ary['bumplimit'] = (int)$op['bumplimit'];
272    $ary['imagelimit'] = (int)$op['imagelimit'];
273    
274    if ($op['sticky']) {
275      $ary['sticky'] = 1;
276      if ($op['undead']) {
277        $ary['sticky_cap'] = STICKY_CAP;
278      }
279    }
280    
281    if ($op['closed']) {
282      $ary['closed'] = 1;
283    }
284    
285    if ($op['archived']) {
286      $ary['archived'] = 1;
287    }
288    
289    $ary['replies'] = (int)$extra['replies'];
290    $ary['images'] = (int)$extra['images'];
291    
292    if (isset($extra['unique_ips'])) {
293      $ary['unique_ips'] = (int)$extra['unique_ips'];
294    }
295    
296    if (SPOILERS) {
297      $ary['custom_spoiler'] = (int)SPOILER_NUM;
298    }
299    
300    return $ary;
301  }
302  
303  function generate_post_json( $var, $threadid, $extra = array(), $banskip = false )
304  {
305  	$COUNTRY_FLAG_ARR = array(
306  		'sp',
307  		'int',
308  	);
309  
310  	$FORCED_ANON_ARR = array(
311  		'b',
312  		'soc'
313  	);
314  
315  	$META_BOARD_ARR = array(
316  		'q'
317  	);
318  	
319  	if (UPLOAD_BOARD) {
320  		$FLASH_TAGS = array(
321  			0 => 'Hentai',
322  			1 => 'Japanese',
323  			2 => 'Anime',
324  			3 => 'Game',
325  			4 => 'Other',
326  			5 => 'Loop',
327  			6 => 'Porn',
328  		);
329  	}
330  	
331  	$SHOW_COUNTRY_FLAGS = $banskip ? in_array( $var['board'], $COUNTRY_FLAG_ARR ) : SHOW_COUNTRY_FLAGS;
332  	$ENABLE_BOARD_FLAGS = $banskip ? false : ENABLE_BOARD_FLAGS;
333  	$META_BOARD         = $banskip ? in_array( $var['board'], $META_BOARD_ARR ) : META_BOARD;
334  	$FORCED_ANON        = $banskip ? in_array( $var['board'], $FORCED_ANON_ARR ) : FORCED_ANON;
335  	
336  	if ($ENABLE_BOARD_FLAGS) {
337  		$board_flags_array = get_board_flags_array();
338  	}
339  	
340  	$country = $var['country'];
341  	
342  	if ($ENABLE_BOARD_FLAGS && isset($board_flags_array[$var['board_flag']])) {
343  		$board_flag = $var['board_flag'];
344  	}
345  	else {
346  	  $board_flag = '';
347  	}
348  
349  	if( $banskip && $var['ext'] ) {
350  		$salt = file_get_contents( '/www/keys/legacy.salt' );
351  		$no   = $var['no'];
352  
353  		$hash         = sha1( $var['board'] . $no . $salt );
354  		$var['thumb'] = $hash;
355  	}
356  
357  	$intern_host = $var['host'];
358  
359  	$unset = array(
360  		'permasage',
361  		'host',
362  		'pwd',
363  		'children',
364      'imgreplycount',
365      'replycount',
366  		'last_modified',
367  		'root',
368  		'4pass_id'
369  	);
370    
371    if ($banskip) {
372      $unset[] = 'protected';
373      $unset[] = 'ua';
374    }
375    
376  	$nunset = $unset;
377  
378  	$var['tim'] = (int)$var['tim'];
379  
380  	if( $var['filedeleted'] == 1 || !$var['ext'] ) {
381  		$arr = array(
382  			'tim',
383  			'w',
384  			'h',
385  			'tn_w',
386  			'tn_h',
387  			'filename',
388  			'ext',
389  			'md5',
390  			'fsize',
391  			'tmd5'
392  		);
393  
394  		foreach( $arr as $key ) {
395  			unset( $var[$key] );
396  		}
397  	}
398  	else {
399  		// FIXME
400  		$var['filename'] = mb_convert_encoding($var['filename'], 'UTF-8', 'UTF-8');
401  	}
402  	
403  	// FIXME
404  	$var['com'] = mb_convert_encoding($var['com'], 'UTF-8', 'UTF-8');
405  	
406  	if( !$var['filedeleted'] ) $nunset[] = 'filedeleted';
407  
408  	// trim it up
409  	foreach( $nunset as $key ) {
410  		unset( $var[$key] );
411  	}
412  	
413  	$is_archived = $var['archived'];
414  
415  	if( $var['resto'] ) {
416  		unset( $var['sticky'] );
417  		unset( $var['closed'] );
418  		unset( $var['archived'] );
419  	}
420  	else {
421  		if (!$var['archived']) {
422  			unset($var['archived']);
423  			unset($var['archived_on']);
424  		}
425  		
426  		if (!$var['closed']) {
427  			unset($var['closed']);
428  		}
429  		
430  		if (!$var['sticky']) {
431  			unset($var['sticky']);
432  		}
433  		else {
434  		  if ($var['undead']) {
435  		    $var['sticky_cap'] = (int)STICKY_CAP;
436  		  }
437  			unset( $var['bumplimit'], $var['imagelimit'] );
438  		}
439  		
440  		if ($var['permaage']) {
441  			unset( $var['bumplimit'] );
442  		}
443  	}
444  	
445  	if (!$var['m_img']) {
446  	  unset($var['m_img']);
447  	}
448  	
449  	if (!$var['since4pass']) {
450  	  unset($var['since4pass']);
451  	}
452  	// April 2024
453  	else if ($var['since4pass'] >= 10000) {
454  		$_stock = april_2024_get_stock_from_s4p($var['since4pass']);
455  		
456  		if ($_stock) {
457  			$var['xa24'] = $_stock;
458  		}
459  		
460  		unset($var['since4pass']);
461  	}
462    
463  	unset($var['permaage'], $var['undead']);
464  	
465  	// clean up names
466  	if( strpos( $var['name'], '</span> <span class="postertrip">' ) !== false ) {
467  		$name        = explode( '</span> <span class="postertrip">', $var['name'] );
468  		$var['name'] = $name[0];
469  		$var['trip'] = $name[1];
470  
471  		if( $var['trip'] && !$var['name'] ) unset( $var['name'] );
472  	}
473  
474  	if( !$banskip && SPOILERS && !$var['resto'] ) $var['custom_spoiler'] = (int)SPOILER_NUM;
475  
476  	$var['spoiler'] = 0;
477  	if( strpos( $var['sub'], 'SPOILER<>' ) === 0 ) {
478  		$var['sub'] = substr( $var['sub'], 9 );
479  		if( !$var['sub'] ) $var['sub'] = '';
480  		$var['spoiler'] = 1;
481  	} else {
482  		unset( $var['spoiler'] );
483  	}
484  
485  	if( $var['sub'] && !$var['resto'] && UPLOAD_BOARD ) {
486  		if( preg_match( '/^(\d+)\|/', $var['sub'], $tag_matches ) ) {
487  			$var['tag'] = $FLASH_TAGS[(int)$tag_matches[1]];
488  			$var['sub'] = preg_replace( '/^(\d+)\|/', '', $var['sub'] );
489  		}
490  	}
491  
492  	if ( !$banskip ) {
493  		if( !$var['id'] || $is_archived ) {
494  			unset( $var['id'] );
495  		} elseif( $var['id'] && $var['no'] == $threadid && $var['capcode'] === 'none') {
496  			$var['id'] = generate_uid( $var['no'], $var['time'], $intern_host );
497  		}
498  	}
499  
500    if ($var['capcode'] == 'none') {
501      if ($ENABLE_BOARD_FLAGS && $board_flag) {
502        unset($var['country']);
503        $var['flag_name'] = board_flag_code_to_name($board_flag);
504      }
505      else if ($SHOW_COUNTRY_FLAGS) {
506        unset( $var['board_flag'] );
507        $var['country_name'] = country_code_to_name($country);
508      }
509      else {
510        unset($var['country']);
511        unset($var['country_name']);
512        unset($var['board_flag']);
513      }
514    }
515    else {
516      unset($var['country']);
517      unset($var['country_name']);
518      unset($var['board_flag']);
519    }
520  
521  	if( ( $FORCED_ANON || $META_BOARD ) && ( $var['capcode'] != 'admin' && $var['capcode'] != 'admin_hl' ) ) {
522  		unset( $var['trip'] );
523  		$var['name']  = 'Anonymous';
524  	}
525  
526  	if( $var['capcode'] == 'none' ) unset( $var['capcode'] );
527  	if( !$banskip ) $var['com'] = auto_link( $var['com'], $threadid );
528  	if( !$banskip && isset( $var['md5'] ) ) $var['md5'] = base64_encode( pack( 'H*', $var['md5'] ) );
529  
530  	if( $var['com'] == '' ) unset( $var['com'] );
531  	if(isset($var['email'])) unset( $var['email'] );
532  	if( $var['sub'] == '' ) unset( $var['sub'] );
533  
534  	if( !empty( $extra ) ) {
535  		foreach( $extra as $key => $val ) {
536  			$var[$key] = $val;
537  		}
538  	}
539  
540  	post_json_force_type( $var );
541  
542  	/// XXX: CHANGE TO TRIM WHITESPACE
543  	return $var;
544  }
545  
546  function generate_index_json( $return = false )
547  {
548  
549  	global $log, $index_rbl;
550  	log_cache( 0, 0 ); // generate all threads
551  
552  	$threads = $log['THREADS'];
553  
554  	$threadcount = count( $threads );
555    
556    // figure out how many replies to print
557    if (defined('REPLIES_SHOWN')) {
558      $replies_shown = REPLIES_SHOWN;
559    }
560    else {
561      $replies_shown = 5;
562    }
563    
564  	// Loop through every page
565  	for( $page = 0; $page < $threadcount; $page += DEF_PAGES ) {
566  	  $file_page_num = $page / DEF_PAGES + 1;
567      
568      if (PAGE_MAX && $file_page_num > PAGE_MAX) {
569        break;
570      }
571      
572  		$thread = $page;
573  		$json   = array();
574  
575  		if( floor( $page / DEF_PAGES ) > $index_rbl ) return;
576  
577  		for( $i = $thread; $i < $thread + DEF_PAGES; $i++ ) {
578  			list( $_unused, $threadid ) = each( $threads );
579  
580  			if( !$threadid ) break;
581  
582        if ($log[$threadid]['sticky'] == 1) {
583          $replies = min(1, $replies_shown);
584        }
585        else {
586          $replies = $replies_shown;
587        }
588        
589  			$json[] = generate_thread_json( $threadid, true, $replies );
590  		}
591  
592  		if( empty( $json ) ) return true; // we've reached the point of no return
593  
594  		$temp = json_encode( array('threads' => $json) );
595  
596  		$filename = INDEX_DIR . ($page / DEF_PAGES + 1) . '.json';
597  		print_page( $filename, $temp, 0, 0 );
598  	}
599  
600  	return true;
601  }
602  
603  //                             ↓ STICK IT TO THE MAN
604  function generate_board_catalogue()
605  {
606  	//$json = generate_index_json( true );
607  
608  	global $log, $index_rbl;
609  	log_cache( 0, 0 ); // generate all threads
610    
611  	$threads     = $log['THREADS'];
612  	$threadcount = count( $threads );
613  	$curpage     = 0;
614    
615  	$json = array();
616    
617    if (defined('REPLIES_SHOWN')) {
618      $replies_shown = REPLIES_SHOWN;
619    }
620    else {
621      $replies_shown = 5;
622    }
623    
624  	for( $page = 0; $page < $threadcount; $page += DEF_PAGES ) {
625  		// Loop through each page...
626  
627  		$thispage = $page;
628  
629  		for( $i = $thispage; $i < $thispage + DEF_PAGES; $i++ ) {
630  			list( $_unused, $threadid ) = each( $threads );
631        
632  			if( !$threadid ) break;
633  			
634        if ($log[$threadid]['sticky'] == 1) {
635          $replies = min(1, $replies_shown);
636        }
637        else {
638          $replies = $replies_shown;
639        }
640  			
641  			$json[$curpage][] = generate_thread_json( $threadid, false, $replies, true );
642  
643  		}
644  
645  		$curpage++;
646  	}
647  
648  	$build = array();
649  
650  	foreach( $json as $page => $threads ) {
651  		$thread = array(
652  			'page'    => $page + 1,
653  			'threads' => $threads
654  		);
655  		$build[] = $thread;
656  	}
657  
658  	$page = json_encode($build);
659  	print_page( INDEX_DIR . 'catalog.json', $page, 0, 0 );
660  }
661  
662  function generate_board_threads_json()
663  {
664  	global $log;
665  	log_cache( 0, 0 );
666  
667  	$threads     = $log['THREADS'];
668  	$threadcount = count( $threads );
669  	$curpage     = 0;
670  	$json        = array();
671  
672  	for( $page = 0; $page < $threadcount; $page += DEF_PAGES ) {
673  		$thispage = $page;
674  
675  		for( $i = $thispage; $i < $thispage + DEF_PAGES; $i++ ) {
676  			list( $_unused, $threadid ) = each( $threads );
677  			
678  			if( !$threadid ) break;
679        
680  			$arr = array(
681          'no' => $threadid,
682          'last_modified' => $log[$threadid]['last_modified'],
683          'replies' => $log[$threadid]['replycount']
684        );
685  
686  			post_json_force_type($arr);
687  
688  			$json[$curpage][] = $arr;
689  
690  		}
691  
692  		$curpage++;
693  	}
694  
695  	foreach( $json as $page => $threads ) {
696  
697  		$build[] = array(
698  			'page'    => $page + 1,
699  			'threads' => $threads
700  		);
701  	}
702  
703  	$page = json_encode( $build );
704  	print_page( INDEX_DIR . 'threads.json', $page, 0, 0 );
705  }
706  
707  function generate_board_archived_json() {
708    $query = "SELECT no FROM `" . BOARD_DIR . "` WHERE archived = 1 AND resto = 0 ORDER BY no ASC";
709    
710    $res = mysql_board_call($query);
711    
712    if (!$res) {
713      return false;
714    }
715    
716    $threads = array();
717    
718    while ($tid = mysql_fetch_row($res)[0]) {
719      $threads[] = $tid;
720    }
721    
722    $page = '[' . implode(',', $threads) . ']';
723    
724  	print_page(INDEX_DIR . 'archive.json', $page, 0, 0);
725  }