<?php

defined('WikyBlog') or die("Not an entry point...");


class checkSyntax{

	
	//returns true or false
	function checkAllFiles($dirPath,&$files,$checkSubDirs=true){
		
		//if it's not a directory, we'll check it.
		if( !is_dir($dirPath) ){
			if( checkSyntax::checkFile($dirPath) === true ){
				return true;
			}
			$files[] = $dirPath;
			return false;
		}
		
		$dh = @opendir($dirPath);
		if( !$dh ){
			trigger_error('Couldn\'t open the directory: '.$dirPath);
			return false;
		}
		
		$dirs = array();
		$done = true;
		while (($file = readdir($dh)) !== false) {
			if($file == '..' || $file == '.'){
				continue;
			}
			$fullPath = $dirPath.'/'.$file;
			
			if( is_dir($fullPath) ){
				$dirs[] = $fullPath;
				continue;
				
			}
			
			if( checkSyntax::checkFile($fullPath) === true ){
				continue;
			}
			$files[] = $fullPath;
			$done = false;
		}
		
		closedir($dh);
		if( $checkSubDirs ){
			foreach($dirs as $dirPath){
				$done = $done && checkSyntax::checkAllFiles($dirPath,$files);
			}
		}
		
		return $done;		
	}
	
	function getFileType($file){
		$type = '';
		$dotSpot = strrpos($file,'.');
		if( $dotSpot !== false ){
			$type = substr($file,$dotSpot);
		}
		return strtolower($type);
	}	
	
	function checkFile($filePath,$show=false){
		global $page;
		$b = 0;
		
		if( !file_exists($filePath) ){
			return true;
		}
		
		$type = checkSyntax::getFileType($filePath);
		if( $type !== '.php' ){
			return true;
		}
		
		$code = file_get_contents($filePath);
		$code = trim($code);
		if( empty($code) ){
			return true;
		}
		$tokens = token_get_all($code);
		
		
		// if( $show ){
		// 	$page->contentA['Tokens'] = 'code: '.showArray($tokens);
		// }
		
		
		$possibleOpen = 0; //for token_get_all() bug
		//entails three tokens "<", "?", and array(0 => 305, 1 => php
		//or "<" and "?php"
		
		$open = false;
		$result = '';
		foreach($tokens as $i => $token){
			
			//because of bugs
			// some versions return arrays for { and some return a string
			if( is_array($token) ){
				$testValue = $token[1];
			}else{
				$testValue = $token;
			}
			
			if( !$open ){
				
				if( is_array($token) ){
					if( $token[0] === T_OPEN_TAG ){
						$possibleOpen = 0;
						$open = true;
						continue;
					}elseif( $token[0] === T_OPEN_TAG_WITH_ECHO ){
						$possibleOpen = 0;
						$open = true;
						continue;
					}

				}
				
				if( $token == '<' ){
					$possibleOpen = 1;
					continue;
				}
				if( $possibleOpen === 1 ){
					if( $testValue == '?' ){
						$possibleOpen = 2;
						$open = true;
						continue;
					}
					if( $testValue == '?php' ){
						$possibleOpen = 0;
						$open = true;
						continue;
					}
				}
				$possibleOpen = 0;
				continue;
			}
			
			if( ($possibleOpen === 2) && $testValue == 'php' ){
				$possibleOpen = 0;
				continue;
			}

			//open
			if( is_array($token) ){
				if( $token[0] === T_CLOSE_TAG ){
					$result .= ';'; //just in case
					$open = false;
					continue;
				}
			}
			
			
			if('{' == $testValue){
				++$b;
			}elseif( '${' == $testValue ){
				++$b;
			}elseif('}' == $testValue){
				--$b;
				if( $b < 0 ){
					if( $show ){
						if( isset($token[2]) ){
							return 'Mismatched Brackets on line '.$token[2].'.';
						}else{
							return 'Mismatched Brackets at token '.$i.'.';
						}
					}
					return false;
				}
			}
			$result .= $testValue;
		}
		
		if( $show ){
			//message(nl2br(htmlspecialchars($code)));
			//message(nl2br(htmlspecialchars($result)));
		}		
	    
		// Unbalanced braces, the eval will error without executing code
		// if( $b !== 0){
		// 	if( $show ){
		// 		return 'Mismatched Brackets';
		// 	}
		// 	return false;
		// }
		
		// Catch potential parse error messages
		if( defined('wbDebug') && wbDebug == true){
			$result = trim($result);
			if( empty($result) ){
				if( $show ){
					return '<b>Notice:</b> Tokenizing resulted in a php file without code.';
				}
				
				return false;	
			}
		}
		
		$err = checkSyntax::checkFile($result);
		if( $show  ){
			if( empty($err) ){
				return 'Unknown Error'; //sometimes eval doesn't output the error
			}else{
				return $err;
			}
		}
		
		if( $code === false ){
			return false;
		}
		return true;
	}
// 	function checkChunk(&$chunk){
// 		ob_start();
// 		$code = eval("if(0){\r\n" . $chunk . "\r\n}"); // Put $code in a dead code sandbox to prevent its execution
// 		return wb::get_clean();
// 	}
		
		
	
	
}
