PHP_CompatInfo
[ class tree: PHP_CompatInfo ] [ index: PHP_CompatInfo ] [ all elements ]

Source for file CompatInfo.php

Documentation is available at CompatInfo.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 3.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available through the world-wide-web at the following url: |
  11. // | http://www.php.net/license/3_0.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Davey Shafik <davey@php.net> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: fsource_PHP_CompatInfo__CompatInfo.php.html,v 1.12 2005/03/06 01:03:34 davey Exp $
  20.  
  21.  
  22.  
  23. /**
  24. * Check Compatibility of chunk of PHP code
  25. * @package PHP_CompatInfo
  26. * @category PHP
  27. */
  28. /**
  29. * An array of function init versions and extension
  30. */
  31. require_once 'PHP/data/func_array.php';
  32.  
  33. /**
  34. * An array of constants and their init versions
  35. */
  36. require_once 'PHP/data/const_array.php';
  37.  
  38. /**
  39. * Check Compatibility of chunk of PHP code
  40. *
  41. * @package PHP_CompatInfo
  42. * @author Davey Shafik <davey@php.net>
  43. * @copyright Copyright 2003 Davey Shafik and Synaptic Media. All Rights Reserved.
  44. * @example docs/examples/checkConstants.php Example that shows minimum version with Constants
  45. * @example docs/examples/parseFile.php Example on how to parse a file
  46. * @example docs/examples/parseDir.php Example on how to parse a directory
  47. * @example docs/examples/parseArray.php Example on using using parseArray() to parse a script
  48. * @example docs/examples/parseString.php Example on how to parse a string
  49. * @example docs/examples/Cli.php Example of using PHP_CompatInfo_Cli
  50. */
  51.  
  52. class PHP_CompatInfo {
  53.  
  54. /**
  55. * @var string Earliest version of PHP to use
  56. */
  57.  
  58. var $latest_version = '4.0.0';
  59.  
  60. /**
  61. * @var boolean Toggle parseDir recursion
  62. */
  63.  
  64. var $recurse_dir = true;
  65.  
  66. /**
  67. * Parse a file for its Compatibility info
  68. *
  69. * @param string $file Path of File to parse
  70. * @param array $options An array of options where:
  71. * 'debug' contains a boolean
  72. * to control whether extra
  73. * ouput is shown.
  74. * 'ignore_functions' contains an array
  75. * of functions to ignore when
  76. * calculating the version needed.
  77. * @access public
  78. * @return Array
  79. */
  80.  
  81. function parseFile($file, $options = array())
  82. {
  83. $options = array_merge(array('debug' => false),$options);
  84. if (!($tokens = $this->_tokenize($file))) {
  85. return false;
  86. }
  87. return $this->_parseTokens($tokens,$options);
  88. }
  89.  
  90. /**
  91. * Parse a string for its Compatibility info
  92. *
  93. * @param string $string PHP Code to parses
  94. * @param array $options An array of options where:
  95. * 'debug' contains a boolean
  96. * to control whether extra
  97. * ouput is shown.
  98. * 'ignore_functions' contains an array
  99. * of functions to ignore when
  100. * calculating the version needed.
  101. * @access public
  102. * @return Array
  103. */
  104.  
  105. function parseString($string, $options = array())
  106. {
  107. $options = array_merge(array('debug' => false),$options);
  108. if (!($tokens = $this->_tokenize($string,true))) {
  109. return false;
  110. }
  111. return $this->_parseTokens($tokens,$options);
  112. }
  113.  
  114. /**
  115. * Parse a directory recursively for its Compatibility info
  116. *
  117. * @see PHP_CompatInfo::_fileList()
  118. * @param string $dir Path of folder to parse
  119. * @param array $options Array of user options where:
  120. * 'file_ext' Contains an array of file
  121. * extensions to parse for PHP
  122. * code. Default: php, php4,
  123. * inc, phtml
  124. * 'recurse_dir' Boolean on whether to
  125. * recursively find files
  126. * 'debug' contains a boolean
  127. * to control whether extra
  128. * ouput is shown.
  129. * 'ignore_files' contains an array of
  130. * files to ignore. File
  131. * names are case insensitive.
  132. * 'ignore_dirs' contains an array of
  133. * directories to ignore.
  134. * Directory names are case
  135. * insensitive.
  136. * 'ignore_functions' contains an array
  137. * of functions to ignore when
  138. * calculating the version needed.
  139. * @access public
  140. * @return array
  141. */
  142.  
  143. function parseDir($dir,$options = array())
  144. {
  145. $files = array();
  146. $latest_version = $this->latest_version;
  147. $extensions = array();
  148. $constants = array();
  149. $ignored = array();
  150. $default_options = array('file_ext' => array('php','php4','inc','phtml'), 'recurse_dir' => true, 'debug' => false, 'ignore_files' => array(), 'ignore_dirs' => array());
  151. $options = array_merge($default_options,$options);
  152. if(is_dir($dir) && is_readable($dir)) {
  153. if($dir{strlen($dir)-1} == '/' || $dir{strlen($dir)-1} == '\\') {
  154. $dir = substr($dir,0,-1);
  155. }
  156. array_map('strtolower', $options['file_ext']);
  157. array_map('strtolower', $options['ignore_files']);
  158. array_map('strtolower', $options['ignore_dirs']);
  159. $files_raw = $this->_fileList($dir,$options);
  160. foreach($files_raw as $file) {
  161. if(in_array(strtolower($file),$options['ignore_files'])) {
  162. $ignored[] = $file;
  163. continue;
  164. }
  165. $file_info = pathinfo($file);
  166. if (isset($file_info['extension']) && in_array(strtolower($file_info['extension']),$options['file_ext'])) {
  167. $tokens = $this->_tokenize($file);
  168. if ($tokens != false) {
  169. $files[$file] = $this->_parseTokens($tokens,$options);
  170. } else {
  171. return false;
  172. }
  173. }
  174. }
  175. foreach($files as $file) {
  176. $cmp = version_compare($latest_version,$file['version']);
  177. if ((int)$cmp === -1) {
  178. $latest_version = $file['version'];
  179. }
  180. foreach($file['extensions'] as $ext) {
  181. if(!in_array($ext,$extensions)) {
  182. $extensions[] = $ext;
  183. }
  184. }
  185. foreach ($file['constants'] as $const) {
  186. if(!in_array($const,$constants)) {
  187. $constants[] = $const;
  188. }
  189. }
  190. }
  191.  
  192. if (sizeof($files) < 1) {
  193. return false;
  194. }
  195.  
  196. $files['constants'] = $constants;
  197. $files['extensions'] = $extensions;
  198. $files['version'] = $latest_version;
  199. $files['ignored_files'] = $ignored;
  200.  
  201. return array_reverse($files);
  202. } else {
  203. return false;
  204. }
  205. }
  206.  
  207. /**
  208. * Alias of parseDir
  209. *
  210. * @uses PHP_CompatInfo::parseDir()
  211. * @access public
  212. */
  213.  
  214. function parseFolder($folder,$options = array()) {
  215. return $this->parseDir($folder,$options);
  216. }
  217.  
  218. /**
  219. * Parse an Array of Files
  220. *
  221. * You can parse an array of Files or Strings, to parse
  222. * strings, $options['is_string'] must be set to true
  223. *
  224. * @param array $files Array of file names or code strings
  225. * @param array $options An array of options where:
  226. * 'file_ext' Contains an array of file
  227. * extensions to parse for PHP
  228. * code. Default: php, php4,
  229. * inc, phtml
  230. * 'debug' contains a boolean
  231. * to control whether extra
  232. * ouput is shown.
  233. * 'is_string' contains a boolean
  234. * which says if the array values
  235. * are strings or file names.
  236. * 'ignore_files' contains an array of
  237. * files to ignore. File
  238. * names are case sensitive.
  239. * 'ignore_functions' contains an array
  240. * of functions to ignore when
  241. * calculating the version needed.
  242. * @access public
  243. * @return array
  244. */
  245.  
  246. function parseArray($files,$options = array()) {
  247. $latest_version = $this->latest_version;
  248. $extensions = array();
  249. $constants = array();
  250. $options = array_merge(array('file_ext' => array('php','php4','inc','phtml'), 'is_string' => false,'debug' => false, 'ignore_files' => array()),$options);
  251. $options['ignore_files'] = array_map("strtolower",$options['ignore_files']);
  252. foreach($files as $file) {
  253. if ($options['is_string'] == false) {
  254. $pathinfo = pathinfo($file);
  255. if (!in_array(strtolower($file),$options['ignore_files']) && in_array($pathinfo['extension'],$options['file_ext'])) {
  256. $tokens = $this->_tokenize($file,$options['is_string']);
  257. if ($tokens != false) {
  258. $files_parsed[$file] = $this->_parseTokens($tokens,$options);
  259. } else {
  260. $files_parsed[$file] = false;
  261. }
  262. } else {
  263. $ignored[] = $file;
  264. }
  265. } else {
  266. $tokens = $this->_tokenize($file,$options['is_string']);
  267. if ($tokens != false) {
  268. $files_parsed[] = $this->_parseTokens($tokens,$options);
  269. } else {
  270. $files_parsed[] = false;
  271. }
  272. }
  273. }
  274.  
  275. foreach($files_parsed as $file) {
  276. if ($file != false) {
  277. $cmp = version_compare($latest_version,$file['version']);
  278. if ((int)$cmp === -1) {
  279. $latest_version = $file['version'];
  280. }
  281. foreach($file['extensions'] as $ext) {
  282. if(!in_array($ext,$extensions)) {
  283. $extensions[] = $ext;
  284. }
  285. }
  286. foreach($file['constants'] as $const) {
  287. if(!in_array($const,$constants)) {
  288. $constants[] = $const;
  289. }
  290. }
  291. }
  292. }
  293.  
  294. $files_parsed['constants'] = $constants;
  295. $files_parsed['extensions'] = $extensions;
  296. $files_parsed['version'] = $latest_version;
  297. $files_parsed['ignored_files'] = isset($ignored) ? $ignored : array();
  298. return array_reverse($files_parsed);
  299. }
  300.  
  301. /**
  302. * Parse the given Tokens
  303. *
  304. * The tokens are those returned by
  305. * token_get_all() which is nicely
  306. * wrapped in PHP_CompatInfo::_tokenize
  307. *
  308. * @param array $tokens Array of PHP Tokens
  309. * @param boolean $debug Show Extra Output
  310. * @access private
  311. * @return array
  312. */
  313.  
  314. function _parseTokens($tokens, $options)
  315. {
  316. $functions = array();
  317. $functions_version = array();
  318. $latest_version = $this->latest_version;
  319. $extensions = array();
  320. $constants = array();
  321. $constant_names = array();
  322. $udf = array();
  323. /* Check for PHP 5 stuffs */
  324. $php5_tokens = @array(
  325. T_ABSTRACT => 'abstract',
  326. T_CATCH => 'catch',
  327. T_FINAL => 'final',
  328. T_INSTANCEOF => 'instanceof',
  329. T_PRIVATE => 'private',
  330. T_PROTECTED => 'protected',
  331. T_PUBLIC => 'public',
  332. T_THROW => 'throw',
  333. T_TRY => 'try',
  334. T_CLONE => 'clone',
  335. T_INTERFACE => 'interface',
  336. T_IMPLEMENTS => 'implements',
  337. );
  338.  
  339. foreach ($php5_tokens as $php5_token => $value) {
  340. if (in_array(array($php5_token, $value), $tokens)
  341. || in_array(array($php5_token, strtoupper($value)), $tokens)
  342. || in_array(array($php5_token, ucfirst($value)), $tokens)) {
  343. $constants[] = $php5_token;
  344. $latest_version = '5.0.0';
  345. break;
  346. }
  347. }
  348. $token_count = sizeof($tokens);
  349. $i = 0;
  350. while ($i < $token_count) {
  351. $found_func = true;
  352. if ($tokens[$i][0] == T_FUNCTION) {
  353. $found_func = false;
  354. }
  355. while ($found_func == false) {
  356. $i += 1;
  357. if ($tokens[$i][0] == T_STRING) {
  358. $found_func = true;
  359. $udf[] = $tokens[$i][1];
  360. }
  361. }
  362. if ($tokens[$i][0] == T_STRING) {
  363. if (isset($tokens[$i + 1]) && ($tokens[$i + 1][0] == '(') && ($tokens[$i - 1][0] != T_DOUBLE_COLON) && ($tokens[$i - 1][0] != T_OBJECT_OPERATOR)) {
  364. $functions[] = $tokens[$i][1];
  365. }
  366. }
  367. if (in_array($tokens[$i][0],$GLOBALS['const']['tokens'])) {
  368. $constants[] = $tokens[$i][0];
  369. }
  370. $i += 1;
  371. }
  372.  
  373. $functions = array_unique($functions);
  374. if (isset($options['ignore_functions'])) {
  375. $options['ignore_functions'] = array_map("strtolower",$options['ignore_functions']);
  376. } else {
  377. $options['ignore_functions'] = array();
  378. }
  379. foreach($functions as $name) {
  380. if (isset($GLOBALS['funcs'][$name]) && (!in_array($name,$udf) && (!in_array($name,$options['ignore_functions'])))) {
  381. if ($options['debug'] == true) {
  382. $functions_version[$GLOBALS['funcs'][$name]['init']][] = array('function' => $name, 'extension' => $GLOBALS['funcs'][$name]['ext']);
  383. }
  384. $cmp = version_compare($latest_version,$GLOBALS['funcs'][$name]['init']);
  385. if ((int)$cmp === -1) {
  386. $latest_version = $GLOBALS['funcs'][$name]['init'];
  387. }
  388. if ((!empty($GLOBALS['funcs'][$name]['ext'])) && ($GLOBALS['funcs'][$name]['ext'] != 'ext_standard') && ($GLOBALS['funcs'][$name]['ext'] != 'zend')) {
  389. $extension = substr($GLOBALS['funcs'][$name]['ext'],4);
  390. if ($extension{0} != '_') {
  391. if(!in_array($extension,$extensions)) {
  392. $extensions[] = $extension;
  393. }
  394. } else {
  395. $ext = substr($extension, 1);
  396. if(!in_array($extension,$extensions)) {
  397. $extensions[] = $extension;
  398. }
  399. }
  400. }
  401. }
  402. }
  403.  
  404. $constants = array_unique($constants);
  405. foreach($constants as $constant) {
  406. $cmp = version_compare($latest_version,$GLOBALS['const'][$constant]['init']);
  407. if ((int)$cmp === -1) {
  408. $latest_version = $GLOBALS['const'][$constant]['init'];
  409. }
  410. if(!in_array($GLOBALS['const'][$constant]['name'],$constant_names)) {
  411. $constant_names[] = $GLOBALS['const'][$constant]['name'];
  412. }
  413. }
  414.  
  415. ksort($functions_version);
  416.  
  417. $functions_version['constants'] = $constant_names;
  418. $functions_version['extensions'] = $extensions;
  419. $functions_version['version'] = $latest_version;
  420. $functions_version = array_reverse($functions_version);
  421. return $functions_version;
  422. }
  423.  
  424. /**
  425. * Token a file or string
  426. *
  427. * @param string $input Filename or PHP code
  428. * @param boolean $is_string Whether or note the input is a string
  429. * @access private
  430. * @return array
  431. */
  432.  
  433. function _tokenize($input,$is_string = false)
  434. {
  435. if ($is_string == false) {
  436. $input = @file_get_contents($input,1);
  437. if (is_string($input)) {
  438. return token_get_all($input);
  439. }
  440. return false;
  441. } else {
  442. return token_get_all($input);
  443. }
  444. }
  445.  
  446. /**
  447. * Retrieve a listing of every file in $directory and
  448. * all subdirectories. Taken from PEAR_PackageFileManager_File
  449. *
  450. * @param string $directory full path to the directory you want the list of
  451. * @access private
  452. * @return array list of files in a directory
  453. */
  454.  
  455. function _fileList($directory,$options)
  456. {
  457. $ret = false;
  458. if (@is_dir($directory) && (!in_array(strtolower($directory),$options['ignore_dirs']))) {
  459. $ret = array();
  460. $d = @dir($directory);
  461. while($d && $entry=$d->read()) {
  462. if ($entry{0} != '.') {
  463. if (is_file($directory . DIRECTORY_SEPARATOR . $entry)) {
  464. $ret[] = $directory . DIRECTORY_SEPARATOR . $entry;
  465. }
  466. if (is_dir($directory . DIRECTORY_SEPARATOR . $entry) && ($options['recurse_dir'] != false)) {
  467. $tmp = $this->_fileList($directory . DIRECTORY_SEPARATOR . $entry,$options);
  468. if (is_array($tmp)) {
  469. foreach($tmp as $ent) {
  470. $ret[] = $ent;
  471. }
  472. }
  473. }
  474. }
  475. }
  476. if ($d) {
  477. $d->close();
  478. }
  479. } else {
  480. return false;
  481. }
  482.  
  483. return $ret;
  484. }
  485. }
  486.  
  487. ?>

Documentation generated on Sat, 05 Mar 2005 20:00:45 -0500 by phpDocumentor 1.3.0RC3