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

Documentation generated on Thu, 6 May 2004 16:59:19 +0100 by phpDocumentor 1.3.0RC3. PEAR Logo Copyright © PHP Group 2004.