PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/ezutils/classes/ezphpcreator.php

https://github.com/StephanBoganskyXrow/ezpublish
PHP | 1363 lines | 848 code | 80 blank | 435 comment | 123 complexity | a9d2fdbb65b31ed4cc7b86dff12bc866 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. //
  3. // Definition of eZPHPCreator class
  4. //
  5. // Created on: <28-Nov-2002 08:28:23 amos>
  6. //
  7. // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  8. // SOFTWARE NAME: eZ Publish
  9. // SOFTWARE RELEASE: 4.1.x
  10. // COPYRIGHT NOTICE: Copyright (C) 1999-2011 eZ Systems AS
  11. // SOFTWARE LICENSE: GNU General Public License v2.0
  12. // NOTICE: >
  13. // This program is free software; you can redistribute it and/or
  14. // modify it under the terms of version 2.0 of the GNU General
  15. // Public License as published by the Free Software Foundation.
  16. //
  17. // This program is distributed in the hope that it will be useful,
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. // GNU General Public License for more details.
  21. //
  22. // You should have received a copy of version 2.0 of the GNU General
  23. // Public License along with this program; if not, write to the Free
  24. // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  25. // MA 02110-1301, USA.
  26. //
  27. //
  28. // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  29. //
  30. /*! \file
  31. */
  32. /*!
  33. \class eZPHPCreator ezphpcreator.php
  34. \ingroup eZUtils
  35. \brief eZPHPCreator provides a simple interface for creating and executing PHP code.
  36. To create PHP code you must create an instance of this class,
  37. add any number of elements you choose with
  38. addDefine(), addVariable(), addVariableUnset(), addVariableUnsetList(),
  39. addSpace(), addText(), addMethodCall(), addCodePiece(), addComment() and
  40. addInclude().
  41. After that you call store() to write all changes to disk.
  42. \code
  43. $php = new eZPHPCreator( 'cache', 'code.php' );
  44. $php->addComment( 'Auto generated' );
  45. $php->addInclude( 'inc.php' );
  46. $php->addVariable( 'count', 10 );
  47. $php->store();
  48. \endcode
  49. To restore PHP code you must create an instance of this class,
  50. check if you can restore it with canRestore() then restore variables with restore().
  51. The class will include PHP file and run all code, once the file is done it will
  52. catch any variables you require and return it to you.
  53. \code
  54. $php = new eZPHPCreator( 'cache', 'code.php' );
  55. if ( $php->canRestore() )
  56. {
  57. $variables = $php->restore( array( 'max_count' => 'count' ) );
  58. print( "Max count was " . $variables['max_count'] );
  59. }
  60. $php->close();
  61. \endcode
  62. */
  63. class eZPHPCreator
  64. {
  65. const VARIABLE = 1;
  66. const SPACE = 2;
  67. const TEXT = 3;
  68. const METHOD_CALL = 4;
  69. const CODE_PIECE = 5;
  70. const EOL_COMMENT = 6;
  71. const INCLUDE_STATEMENT = 7;
  72. const VARIABLE_UNSET = 8;
  73. const DEFINE = 9;
  74. const VARIABLE_UNSET_LIST = 10;
  75. const RAW_VARIABLE = 11;
  76. const VARIABLE_ASSIGNMENT = 1;
  77. const VARIABLE_APPEND_TEXT = 2;
  78. const VARIABLE_APPEND_ELEMENT = 3;
  79. const INCLUDE_ONCE_STATEMENT = 1;
  80. const INCLUDE_ALWAYS_STATEMENT = 2;
  81. const METHOD_CALL_PARAMETER_VALUE = 1;
  82. const METHOD_CALL_PARAMETER_VARIABLE = 2;
  83. /*!
  84. Initializes the creator with the directory path \a $dir and filename \a $file.
  85. */
  86. function eZPHPCreator( $dir, $file, $prefix = '', $options = array() )
  87. {
  88. $this->PHPDir = $dir;
  89. $this->PHPFile = $file;
  90. $this->FilePrefix = $prefix;
  91. $this->FileResource = false;
  92. $this->Elements = array();
  93. $this->TextChunks = array();
  94. $this->TemporaryCounter = 0;
  95. if ( isset( $options['spacing'] ) and ( $options['spacing'] == 'disabled') )
  96. {
  97. $this->Spacing = false;
  98. }
  99. else
  100. {
  101. $this->Spacing = true;
  102. }
  103. if ( isset( $options['clustering'] ) )
  104. {
  105. $this->ClusteringEnabled = true;
  106. $this->ClusterFileScope = $options['clustering'];
  107. }
  108. else
  109. {
  110. $this->ClusteringEnabled = false;
  111. }
  112. $this->ClusterHandler = null;
  113. }
  114. //@{
  115. /*!
  116. Adds a new define statement to the code with the name \a $name and value \a $value.
  117. The parameter \a $caseSensitive determines if the define should be made case sensitive or not.
  118. Example:
  119. \code
  120. $php->addDefine( 'MY_CONSTANT', 5 );
  121. \endcode
  122. Would result in the PHP code.
  123. \code
  124. define( 'MY_CONSTANT', 5 );
  125. \endcode
  126. \param $parameters Optional parameters, can be any of the following:
  127. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  128. \note \a $name must start with a letter or underscore, followed by any number of letters, numbers, or underscores.
  129. See http://php.net/manual/en/language.constants.php for more information.
  130. \sa http://php.net/manual/en/function.define.php
  131. */
  132. function addDefine( $name, $value, $caseSensitive = true, $parameters = array() )
  133. {
  134. $element = array( eZPHPCreator::DEFINE,
  135. $name,
  136. $value,
  137. $caseSensitive,
  138. $parameters );
  139. $this->Elements[] = $element;
  140. }
  141. /*!
  142. Adds a new raw variable tothe code with the name \a $name and value \a $value.
  143. Example:
  144. \code
  145. $php->addVariable( 'TransLationRoot', $cache['root'] );
  146. \endcode
  147. This function makes use of PHP's var_export() function which is optimized
  148. for this task.
  149. */
  150. function addRawVariable( $name, $value )
  151. {
  152. $element = array( eZPHPCreator::RAW_VARIABLE, $name, $value );
  153. $this->Elements[] = $element;
  154. }
  155. /*!
  156. Adds a new variable to the code with the name \a $name and value \a $value.
  157. Example:
  158. \code
  159. $php->addVariable( 'offset', 5 );
  160. $php->addVariable( 'text', 'some more text', eZPHPCreator::VARIABLE_APPEND_TEXT );
  161. $php->addVariable( 'array', 42, eZPHPCreator::VARIABLE_APPEND_ELEMENT );
  162. \endcode
  163. Would result in the PHP code.
  164. \code
  165. $offset = 5;
  166. $text .= 'some more text';
  167. $array[] = 42;
  168. \endcode
  169. \param $assignmentType Controls the way the value is assigned, choose one of the following:
  170. - \b eZPHPCreator::VARIABLE_ASSIGNMENT, assign using \c = (default)
  171. - \b eZPHPCreator::VARIABLE_APPEND_TEXT, append using text concat operator \c .
  172. - \b eZPHPCreator::VARIABLE_APPEND_ELEMENT, append element to array using append operator \c []
  173. \param $parameters Optional parameters, can be any of the following:
  174. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  175. - \a full-tree, Whether to displays array values as one large expression (\c true) or
  176. split it up into multiple variables (\c false)
  177. */
  178. function addVariable( $name, $value, $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT,
  179. $parameters = array() )
  180. {
  181. $element = array( eZPHPCreator::VARIABLE,
  182. $name,
  183. $value,
  184. $assignmentType,
  185. $parameters );
  186. $this->Elements[] = $element;
  187. }
  188. /*!
  189. Adds code to unset a variable with the name \a $name.
  190. Example:
  191. \code
  192. $php->addVariableUnset( 'offset' );
  193. \endcode
  194. Would result in the PHP code.
  195. \code
  196. unset( $offset );
  197. \endcode
  198. \param $parameters Optional parameters, can be any of the following:
  199. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  200. \sa http://php.net/manual/en/function.unset.php
  201. */
  202. function addVariableUnset( $name,
  203. $parameters = array() )
  204. {
  205. $element = array( eZPHPCreator::VARIABLE_UNSET,
  206. $name,
  207. $parameters );
  208. $this->Elements[] = $element;
  209. }
  210. /*!
  211. Adds code to unset a list of variables with name from \a $list.
  212. Example:
  213. \code
  214. $php->addVariableUnsetList( array ( 'var1', 'var2' ) );
  215. \endcode
  216. Would result in the PHP code.
  217. \code
  218. unset( $var1, $var2 );
  219. \endcode
  220. \param $parameters Optional parameters, can be any of the following:
  221. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  222. \sa http://php.net/manual/en/function.unset.php
  223. */
  224. function addVariableUnsetList( $list,
  225. $parameters = array() )
  226. {
  227. $element = array( eZPHPCreator::VARIABLE_UNSET_LIST,
  228. $list,
  229. $parameters );
  230. $this->Elements[] = $element;
  231. }
  232. /*!
  233. Adds some space to the code in form of newlines. The number of lines
  234. is controlled with \a $lines which is \c 1 by default.
  235. You can use this to get more readable PHP code.
  236. Example:
  237. \code
  238. $php->addSpace( 1 );
  239. \endcode
  240. */
  241. function addSpace( $lines = 1 )
  242. {
  243. $element = array( eZPHPCreator::SPACE,
  244. $lines );
  245. $this->Elements[] = $element;
  246. }
  247. /*!
  248. Adds some plain text to the code. The text will be placed
  249. outside of PHP start and end markers and will in principle
  250. work as printing the text.
  251. Example:
  252. \code
  253. $php->addText( 'Print me!' );
  254. \endcode
  255. */
  256. function addText( $text )
  257. {
  258. $element = array( eZPHPCreator::TEXT,
  259. $text );
  260. $this->Elements[] = $element;
  261. }
  262. /*!
  263. Adds code to call the method \a $methodName on the object named \a $objectName,
  264. \a $methodParameters should be an array with parameter entries where each entry contains:
  265. - \a 0, The parameter value
  266. - \a 1 (\em optional), The type of parameter, is one of:
  267. - \b eZPHPCreator::METHOD_CALL_PARAMETER_VALUE, Use value directly (default if this entry is missing)
  268. - \b eZPHPCreator::METHOD_CALL_PARAMETER_VARIABLE, Use value as the name of the variable.
  269. Optionally the \a $returnValue parameter can be used to decide what should be done
  270. with the return value of the method call. It can either be \c false which means
  271. to do nothing or an array with the following entries.
  272. - \a 0, The name of the variable to assign the value to
  273. - \a 1 (\em optional), The type of assignment, uses the same value as addVariable().
  274. \param $parameters Optional parameters, can be any of the following:
  275. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  276. Example:
  277. \code
  278. $php->addMethodCall( 'node', 'name', array(), array( 'name' ) );
  279. $php->addMethodCall( 'php', 'addMethodCall',
  280. array( array( 'node' ), array( 'name' ) ) );
  281. \endcode
  282. Would result in the PHP code.
  283. \code
  284. $name = $node->name();
  285. $php->addMethodCall( 'node', 'name' );
  286. \endcode
  287. */
  288. function addMethodCall( $objectName, $methodName, $methodParameters, $returnValue = false, $parameters = array() )
  289. {
  290. $element = array( eZPHPCreator::METHOD_CALL,
  291. $objectName,
  292. $methodName,
  293. $methodParameters,
  294. $returnValue,
  295. $parameters );
  296. $this->Elements[] = $element;
  297. }
  298. /*!
  299. Adds custom PHP code to the file, you should only use this a last resort if any
  300. of the other \em add functions done give you the required result.
  301. \param $code Contains the code as text, the text will not be modified (except for spacing).
  302. This means that each expression must be ended with a newline even if it's just one.
  303. \param $parameters Optional parameters, can be any of the following:
  304. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  305. Example:
  306. \code
  307. $php->addCodePiece( "if ( \$value > 2 )\n{\n \$value = 2;\n}\n" );
  308. \endcode
  309. Would result in the PHP code.
  310. \code
  311. if ( $value > 2 )
  312. {
  313. $value = 2;
  314. }
  315. \endcode
  316. */
  317. function addCodePiece( $code, $parameters = array() )
  318. {
  319. $element = array( eZPHPCreator::CODE_PIECE,
  320. $code,
  321. $parameters );
  322. $this->Elements[] = $element;
  323. }
  324. /*!
  325. Adds a comment to the code, the comment will be display using multiple end-of-line
  326. comments (//), one for each newline in the text \a $comment.
  327. \param $eol Whether to add a newline at the last comment line
  328. \param $whitespaceHandling Whether to remove trailing whitespace from each line
  329. \param $parameters Optional parameters, can be any of the following:
  330. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  331. Example:
  332. \code
  333. $php->addComment( "This file is auto generated\nDo not edit!" );
  334. \endcode
  335. Would result in the PHP code.
  336. \code
  337. // This file is auto generated
  338. // Do not edit!
  339. \endcode
  340. */
  341. function addComment( $comment, $eol = true, $whitespaceHandling = true, $parameters = array() )
  342. {
  343. $element = array( eZPHPCreator::EOL_COMMENT,
  344. $comment,
  345. array_merge( $parameters,
  346. array( 'eol' => $eol,
  347. 'whitespace-handling' => $whitespaceHandling ) ) );
  348. $this->Elements[] = $element;
  349. }
  350. /*!
  351. Adds an include statement to the code, the file to include is \a $file.
  352. \param $type What type of include statement to use, can be one of the following:
  353. - \b eZPHPCreator::INCLUDE_ONCE_STATEMENT, use \em include_once()
  354. - \b eZPHPCreator::INCLUDE_ALWAYS_STATEMENT, use \em include()
  355. \param $parameters Optional parameters, can be any of the following:
  356. - \a spacing, The number of spaces to place before each code line, default is \c 0.
  357. Example:
  358. \code
  359. $php->addInclude( 'lib/ezutils/classes/ezphpcreator.php' );
  360. \endcode
  361. Would result in the PHP code.
  362. \code
  363. //include_once( 'lib/ezutils/classes/ezphpcreator.php' );
  364. \endcode
  365. */
  366. function addInclude( $file, $type = eZPHPCreator::INCLUDE_ONCE_STATEMENT, $parameters = array() )
  367. {
  368. $element = array( eZPHPCreator::INCLUDE_STATEMENT,
  369. $file,
  370. $type,
  371. $parameters );
  372. $this->Elements[] = $element;
  373. }
  374. //@}
  375. /*!
  376. \static
  377. Creates a variable statement with an assignment type and returns it.
  378. \param $variableName The name of the variable
  379. \param $assignmentType What kind of assignment to use, is one of the following;
  380. - \b eZPHPCreator::VARIABLE_ASSIGNMENT, assign using \c =
  381. - \b eZPHPCreator::VARIABLE_APPEND_TEXT, append to text using \c .
  382. - \b eZPHPCreator::VARIABLE_APPEND_ELEMENT, append to array using \c []
  383. \param $variableParameters Optional parameters for the statement
  384. */
  385. static function variableNameText( $variableName, $assignmentType, $variableParameters = array() )
  386. {
  387. $text = '$' . $variableName;
  388. if ( $assignmentType == eZPHPCreator::VARIABLE_ASSIGNMENT )
  389. {
  390. $text .= ' = ';
  391. }
  392. else if ( $assignmentType == eZPHPCreator::VARIABLE_APPEND_TEXT )
  393. {
  394. $text .= ' .= ';
  395. }
  396. else if ( $assignmentType == eZPHPCreator::VARIABLE_APPEND_ELEMENT )
  397. {
  398. $text .= '[] = ';
  399. }
  400. return $text;
  401. }
  402. /*!
  403. Creates a text representation of the value \a $value which can
  404. be placed in files and be read back by a PHP parser as it was.
  405. The type of the values determines the output, it can be one of the following.
  406. - boolean, becomes \c true or \c false
  407. - null, becomes \c null
  408. - string, adds \ (backslash) to backslashes, double quotes, dollar signs and newlines.
  409. Then wraps the whole string in " (double quotes).
  410. - numeric, displays the value as-is.
  411. - array, expands all value recursively using this function
  412. - object, creates a representation of an object creation if the object has \c serializeData implemented.
  413. \param $column Determines the starting column in which the text will be placed.
  414. This is used for expanding arrays and objects which can span multiple lines.
  415. \param $iteration The current iteration, starts at 0 and increases with 1 for each recursive call
  416. \param $maxIterations The maximum number of iterations to allow, if the iteration
  417. exceeds this the array or object will be split into multiple variables.
  418. Can be set to \c false to the array or object as-is.
  419. \note This function can be called statically if \a $maxIterations is set to \c false
  420. */
  421. function thisVariableText( $value, $column = 0, $iteration = 0, $maxIterations = 2 )
  422. {
  423. if ( isset( $this->Spacing ) and !$this->Spacing )
  424. {
  425. return var_export( $value, true );
  426. }
  427. if ( $value === true )
  428. $text = 'true';
  429. else if ( $value === false )
  430. $text = 'false';
  431. else if ( $value === null )
  432. $text = 'null';
  433. else if ( is_string( $value ) )
  434. {
  435. $valueText = str_replace( array( "\\",
  436. "\"",
  437. "\$",
  438. "\n" ),
  439. array( "\\\\",
  440. "\\\"",
  441. "\\$",
  442. "\\n" ),
  443. $value );
  444. $text = "\"$valueText\"";
  445. }
  446. else if ( is_numeric( $value ) )
  447. $text = $value;
  448. else if ( is_object( $value ) )
  449. {
  450. if ( $maxIterations !== false and
  451. $iteration > $maxIterations )
  452. {
  453. $temporaryVariableName = $this->temporaryVariableName( 'obj' );
  454. $this->writeVariable( $temporaryVariableName, $value );
  455. $text = '$' . $temporaryVariableName;
  456. }
  457. else
  458. {
  459. $text = '';
  460. if ( method_exists( $value, 'serializeData' ) )
  461. {
  462. $serializeData = $value->serializeData();
  463. $className = $serializeData['class_name'];
  464. $text = "new $className(";
  465. $column += strlen( $text );
  466. $parameters = $serializeData['parameters'];
  467. $variables = $serializeData['variables'];
  468. $i = 0;
  469. foreach ( $parameters as $parameter )
  470. {
  471. if ( $i > 0 )
  472. {
  473. $text .= ",\n" . str_repeat( ' ', $column );
  474. }
  475. $variableName = $variables[$parameter];
  476. $variableValue = $value->$variableName;
  477. $keyText = " ";
  478. $text .= $keyText . $this->thisVariableText( $variableValue, $column + strlen( $keyText ), $iteration + 1, $maxIterations );
  479. ++$i;
  480. }
  481. if ( $i > 0 )
  482. $text .= ' ';
  483. $text .= ')';
  484. }
  485. }
  486. }
  487. else if ( is_array( $value ) )
  488. {
  489. if ( $maxIterations !== false and
  490. $iteration > $maxIterations )
  491. {
  492. $temporaryVariableName = $this->temporaryVariableName( 'arr' );
  493. $this->writeVariable( $temporaryVariableName, $value );
  494. $text = '$' . $temporaryVariableName;
  495. }
  496. else
  497. {
  498. $text = 'array(';
  499. $column += strlen( $text );
  500. $valueKeys = array_keys( $value );
  501. $isIndexed = true;
  502. for ( $i = 0; $i < count( $valueKeys ); ++$i )
  503. {
  504. if ( $i !== $valueKeys[$i] )
  505. {
  506. $isIndexed = false;
  507. break;
  508. }
  509. }
  510. $i = 0;
  511. foreach ( $valueKeys as $key )
  512. {
  513. if ( $i > 0 )
  514. {
  515. $text .= ",\n" . str_repeat( ' ', $column );
  516. }
  517. $element = $value[$key];
  518. $keyText = ' ';
  519. if ( !$isIndexed )
  520. {
  521. if ( is_int( $key ) )
  522. $keyText = $key;
  523. else
  524. $keyText = "\"" . str_replace( array( "\\",
  525. "\"",
  526. "\n" ),
  527. array( "\\\\",
  528. "\\\"",
  529. "\\n" ),
  530. $key ) . "\"";
  531. $keyText = " $keyText => ";
  532. }
  533. $text .= $keyText . $this->thisVariableText( $element, $column + strlen( $keyText ), $iteration + 1, $maxIterations );
  534. ++$i;
  535. }
  536. if ( $i > 0 )
  537. $text .= ' ';
  538. $text .= ')';
  539. }
  540. }
  541. else
  542. $text = 'null';
  543. return $text;
  544. }
  545. static function variableText( $value, $column = 0, $iteration = 0, $maxIterations = false )
  546. {
  547. // the last parameter will always be ignored
  548. $maxIterations = false;
  549. if ( $value === true )
  550. $text = 'true';
  551. else if ( $value === false )
  552. $text = 'false';
  553. else if ( $value === null )
  554. $text = 'null';
  555. else if ( is_string( $value ) )
  556. {
  557. $valueText = str_replace( array( "\\",
  558. "\"",
  559. "\$",
  560. "\n" ),
  561. array( "\\\\",
  562. "\\\"",
  563. "\\$",
  564. "\\n" ),
  565. $value );
  566. $text = "\"$valueText\"";
  567. }
  568. else if ( is_numeric( $value ) )
  569. $text = $value;
  570. else if ( is_object( $value ) )
  571. {
  572. $text = '';
  573. if ( method_exists( $value, 'serializeData' ) )
  574. {
  575. $serializeData = $value->serializeData();
  576. $className = $serializeData['class_name'];
  577. $text = "new $className(";
  578. $column += strlen( $text );
  579. $parameters = $serializeData['parameters'];
  580. $variables = $serializeData['variables'];
  581. $i = 0;
  582. foreach ( $parameters as $parameter )
  583. {
  584. if ( $i > 0 )
  585. {
  586. $text .= ",\n" . str_repeat( ' ', $column );
  587. }
  588. $variableName = $variables[$parameter];
  589. $variableValue = $value->$variableName;
  590. $keyText = " ";
  591. $text .= $keyText . eZPHPCreator::variableText( $variableValue, $column + strlen( $keyText ), $iteration + 1 );
  592. ++$i;
  593. }
  594. if ( $i > 0 )
  595. $text .= ' ';
  596. $text .= ')';
  597. }
  598. }
  599. else if ( is_array( $value ) )
  600. {
  601. $text = 'array(';
  602. $column += strlen( $text );
  603. $valueKeys = array_keys( $value );
  604. $isIndexed = true;
  605. for ( $i = 0; $i < count( $valueKeys ); ++$i )
  606. {
  607. if ( $i !== $valueKeys[$i] )
  608. {
  609. $isIndexed = false;
  610. break;
  611. }
  612. }
  613. $i = 0;
  614. foreach ( $valueKeys as $key )
  615. {
  616. if ( $i > 0 )
  617. {
  618. $text .= ",\n" . str_repeat( ' ', $column );
  619. }
  620. $element = $value[$key];
  621. $keyText = ' ';
  622. if ( !$isIndexed )
  623. {
  624. if ( is_int( $key ) )
  625. $keyText = $key;
  626. else
  627. $keyText = "\"" . str_replace( array( "\\",
  628. "\"",
  629. "\n" ),
  630. array( "\\\\",
  631. "\\\"",
  632. "\\n" ),
  633. $key ) . "\"";
  634. $keyText = " $keyText => ";
  635. }
  636. $text .= $keyText . eZPHPCreator::variableText( $element, $column + strlen( $keyText ), $iteration + 1 );
  637. ++$i;
  638. }
  639. if ( $i > 0 )
  640. $text .= ' ';
  641. $text .= ')';
  642. }
  643. else
  644. $text = 'null';
  645. return $text;
  646. }
  647. /*!
  648. \static
  649. Splits \a $text into multiple lines using \a $splitString for splitting.
  650. For each line it will prepend the string \a $spacingString n times as specified by \a $spacing.
  651. It will try to be smart and not do anything when \a $spacing is set to \c 0.
  652. \param $skipEmptyLines If \c true it will not prepend the string for empty lines.
  653. \param $spacing Must be a positive number, \c 0 means to not prepend anything.
  654. */
  655. static function prependSpacing( $text, $spacing, $skipEmptyLines = true, $spacingString = " ", $splitString = "\n" )
  656. {
  657. if ( $spacing == 0 )
  658. return $text;
  659. $textArray = explode( $splitString, $text );
  660. $newTextArray = array();
  661. foreach ( $textArray as $text )
  662. {
  663. if ( trim( $text ) != '' )
  664. $textLine = str_repeat( $spacingString, $spacing ) . $text;
  665. else
  666. $textLine = $text;
  667. $newTextArray[] = $textLine;
  668. }
  669. return implode( $splitString, $newTextArray );
  670. }
  671. //@{
  672. /*!
  673. Opens the file for writing and sets correct file permissions.
  674. \return The current file resource or \c false if it failed to open the file.
  675. \note The file name and path is supplied to the constructor of this class.
  676. \note Multiple calls to this method will only open the file once.
  677. */
  678. function open( $atomic = false )
  679. {
  680. if ( $this->ClusteringEnabled )
  681. return true;
  682. if ( !$this->FileResource )
  683. {
  684. if ( !file_exists( $this->PHPDir ) )
  685. {
  686. eZDir::mkdir( $this->PHPDir, false, true );
  687. }
  688. $path = $this->PHPDir . '/' . $this->PHPFile;
  689. $oldumask = umask( 0 );
  690. $pathExisted = file_exists( $path );
  691. if ( $atomic )
  692. {
  693. $this->isAtomic = true;
  694. $this->requestedFilename = $path;
  695. $uniqid = md5( uniqid( "ezp". getmypid(), true ) );
  696. $path .= ".$uniqid";
  697. $this->tmpFilename = $path;
  698. }
  699. $ini = eZINI::instance();
  700. $perm = octdec( $ini->variable( 'FileSettings', 'StorageFilePermissions' ) );
  701. $this->FileResource = @fopen( $this->FilePrefix . $path, "w" );
  702. if ( !$this->FileResource )
  703. eZDebug::writeError( "Could not open file '$path' for writing, perhaps wrong permissions" );
  704. if ( $this->FileResource and
  705. !$pathExisted )
  706. chmod( $path, $perm );
  707. umask( $oldumask );
  708. }
  709. return $this->FileResource;
  710. }
  711. /*!
  712. Closes the currently open file if any.
  713. */
  714. function close()
  715. {
  716. if ( $this->ClusteringEnabled )
  717. {
  718. $this->ClusterHandler = null;
  719. return;
  720. }
  721. if ( $this->FileResource )
  722. {
  723. fclose( $this->FileResource );
  724. if ( $this->isAtomic )
  725. {
  726. eZFile::rename( $this->tmpFilename, $this->requestedFilename );
  727. }
  728. $this->FileResource = false;
  729. }
  730. }
  731. /*!
  732. \return \c true if the file and path already exists.
  733. \note The file name and path is supplied to the constructor of this class.
  734. */
  735. function exists()
  736. {
  737. $path = $this->PHPDir . '/' . $this->PHPFile;
  738. if ( !$this->ClusteringEnabled )
  739. return file_exists( $path );
  740. if ( !$this->ClusterHandler )
  741. {
  742. $this->ClusterHandler = eZClusterFileHandler::instance();
  743. }
  744. return $this->ClusterHandler->fileExists( $path );
  745. }
  746. /*!
  747. \return \c true if file exists and can be restored.
  748. \param $timestamp The timestamp to check the modification time of the file against,
  749. if the modification time is larger or equal to \a $timestamp
  750. the file can be restored. Otherwise the file is considered too old.
  751. \note The file name and path is supplied to the constructor of this class.
  752. */
  753. function canRestore( $timestamp = false )
  754. {
  755. $path = $this->PHPDir . '/' . $this->PHPFile;
  756. if ( $this->ClusteringEnabled )
  757. {
  758. if ( !$this->ClusterHandler )
  759. {
  760. $this->ClusterHandler = eZClusterFileHandler::instance( $path );
  761. }
  762. // isExpired() expects -1 to disable expiry check
  763. $expiry = ( $timestamp === false ) ? -1 : $timestamp;
  764. return !$this->ClusterHandler->isExpired( $expiry, time(), null );
  765. }
  766. $canRestore = file_exists( $path );
  767. if ( $timestamp !== false and
  768. $canRestore )
  769. {
  770. $cacheModifierTime = filemtime( $path );
  771. $canRestore = ( $cacheModifierTime >= $timestamp );
  772. }
  773. return $canRestore;
  774. }
  775. /*!
  776. Tries to restore the PHP file and fetch the defined variables in \a $variableDefinitions.
  777. This basically means including the file using include().
  778. \param $variableDefinitions Associative array with the return variable name being the key
  779. matched variable as value.
  780. \return An associatve array with the variables that were found according to \a $variableDefinitions.
  781. Example:
  782. \code
  783. $values = $php->restore( array( 'MyValue' => 'node' ) );
  784. print( $values['MyValue'] );
  785. \endcode
  786. \note The file name and path is supplied to the constructor of this class.
  787. */
  788. function restore( $variableDefinitions )
  789. {
  790. $returnVariables = array();
  791. $path = $this->PHPDir . '/' . $this->PHPFile;
  792. if ( !$this->ClusteringEnabled )
  793. {
  794. $returnVariables = $this->_restoreCall( $path, false, $variableDefinitions );
  795. }
  796. else
  797. {
  798. if ( !$this->ClusterHandler )
  799. {
  800. $this->ClusterHandler = eZClusterFileHandler::instance( $path );
  801. }
  802. $returnVariables = $this->ClusterHandler->processFile( array( $this, '_restoreCall' ), null, $variableDefinitions );
  803. }
  804. return $returnVariables;
  805. }
  806. /*!
  807. \private
  808. Processes the PHP file and returns the specified data.
  809. */
  810. function _restoreCall( $path, $mtime, $variableDefinitions )
  811. {
  812. $returnVariables = array();
  813. include( $path );
  814. foreach ( $variableDefinitions as $variableReturnName => $variableName )
  815. {
  816. $variableRequired = true;
  817. $variableDefault = false;
  818. if ( is_array( $variableName ) )
  819. {
  820. $variableDefinition = $variableName;
  821. $variableName = $variableDefinition['name'];
  822. $variableRequired = $variableDefinition['required'];
  823. if ( isset( $variableDefinition['default'] ) )
  824. $variableDefault = $variableDefinition['default'];
  825. }
  826. if ( isset( $$variableName ) )
  827. {
  828. $returnVariables[$variableReturnName] = $$variableName;
  829. }
  830. else if ( $variableRequired )
  831. {
  832. eZDebug::writeError( "Variable '$variableName' is not present in cache '$path'", __METHOD__ );
  833. }
  834. else
  835. {
  836. $returnVariables[$variableReturnName] = $variableDefault;
  837. }
  838. }
  839. return $returnVariables;
  840. }
  841. /*!
  842. Stores the PHP cache, returns false if the cache file could not be created.
  843. */
  844. function store( $atomic = false )
  845. {
  846. if ( $this->open( $atomic ) )
  847. {
  848. $this->write( "<?php\n" );
  849. $this->writeElements();
  850. $this->write( "?>\n" );
  851. $this->writeChunks();
  852. $this->flushChunks();
  853. $this->close();
  854. if ( !$this->ClusteringEnabled )
  855. {
  856. $perm = octdec( eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ) );
  857. chmod( eZDir::path( array( $this->PHPDir, $this->PHPFile ) ), $perm );
  858. }
  859. // Write log message to storage.log
  860. eZLog::writeStorageLog( $this->PHPFile, $this->PHPDir . '/' );
  861. return true;
  862. }
  863. else
  864. {
  865. eZDebug::writeError( "Failed to open file '" . $this->PHPDir . '/' . $this->PHPFile . "'", __METHOD__ );
  866. return false;
  867. }
  868. }
  869. /*!
  870. Creates a text string out of all elements and returns it.
  871. \note Calling this multiple times will resulting text processing each time.
  872. */
  873. function fetch( $addPHPMarkers = true )
  874. {
  875. if ( $addPHPMarkers )
  876. $this->write( "<?php\n" );
  877. $this->writeElements();
  878. if ( $addPHPMarkers )
  879. $this->write( "?>\n" );
  880. $text = implode( '', $this->TextChunks );
  881. $this->flushChunks();
  882. return $text;
  883. }
  884. //@}
  885. /*!
  886. \private
  887. */
  888. function writeChunks()
  889. {
  890. $count = count( $this->TextChunks );
  891. if ( $this->ClusteringEnabled )
  892. {
  893. $text = '';
  894. for ( $i = 0; $i < $count; ++$i )
  895. $text .= $this->TextChunks[$i];
  896. $filePath = $this->FilePrefix . $this->PHPDir . '/' . $this->PHPFile;
  897. if ( !$this->ClusterHandler )
  898. {
  899. $this->ClusterHandler = eZClusterFileHandler::instance();
  900. }
  901. $this->ClusterHandler->fileStoreContents( $filePath, $text, $this->ClusterFileScope, 'php' );
  902. return;
  903. }
  904. for ( $i = 0; $i < $count; ++$i )
  905. {
  906. $text = $this->TextChunks[$i];
  907. fwrite( $this->FileResource, $text );
  908. }
  909. }
  910. /*!
  911. \private
  912. */
  913. function flushChunks()
  914. {
  915. $this->TextChunks = array();
  916. }
  917. /*!
  918. \private
  919. */
  920. function write( $text )
  921. {
  922. $this->TextChunks[] = $text;
  923. }
  924. /*!
  925. \private
  926. */
  927. function writeElements()
  928. {
  929. foreach( $this->Elements as $element )
  930. {
  931. if ( $element[0] == eZPHPCreator::DEFINE )
  932. {
  933. $this->writeDefine( $element );
  934. }
  935. else if ( $element[0] == eZPHPCreator::RAW_VARIABLE )
  936. {
  937. $this->writeRawVariable( $element[1], $element[2] );
  938. }
  939. else if ( $element[0] == eZPHPCreator::VARIABLE )
  940. {
  941. $this->writeVariable( $element[1], $element[2], $element[3], $element[4] );
  942. }
  943. else if ( $element[0] == eZPHPCreator::VARIABLE_UNSET )
  944. {
  945. $this->writeVariableUnset( $element );
  946. }
  947. else if ( $element[0] == eZPHPCreator::VARIABLE_UNSET_LIST )
  948. {
  949. $this->writeVariableUnsetList( $element );
  950. }
  951. else if ( $element[0] == eZPHPCreator::SPACE )
  952. {
  953. $this->writeSpace( $element );
  954. }
  955. else if ( $element[0] == eZPHPCreator::TEXT )
  956. {
  957. $this->writeText( $element );
  958. }
  959. else if ( $element[0] == eZPHPCreator::METHOD_CALL )
  960. {
  961. $this->writeMethodCall( $element );
  962. }
  963. else if ( $element[0] == eZPHPCreator::CODE_PIECE )
  964. {
  965. $this->writeCodePiece( $element );
  966. }
  967. else if ( $element[0] == eZPHPCreator::EOL_COMMENT )
  968. {
  969. $this->writeComment( $element );
  970. }
  971. else if ( $element[0] == eZPHPCreator::INCLUDE_STATEMENT )
  972. {
  973. $this->writeInclude( $element );
  974. }
  975. }
  976. }
  977. /*!
  978. \private
  979. */
  980. function writeDefine( $element )
  981. {
  982. $name = $element[1];
  983. $value = $element[2];
  984. $caseSensitive = $element[3];
  985. $parameters = $element[4];
  986. $text = '';
  987. if ( $this->Spacing )
  988. {
  989. $spacing = 0;
  990. if ( isset( $parameters['spacing'] ) )
  991. $spacing = $parameters['spacing'];
  992. $text = str_repeat( ' ', $spacing );
  993. }
  994. $nameText = $this->thisVariableText( $name, 0 );
  995. $valueText = $this->thisVariableText( $value, 0 );
  996. $text .= "define( $nameText, $valueText";
  997. if ( !$caseSensitive )
  998. $text .= ", true";
  999. $text .= " );\n";
  1000. $this->write( $text );
  1001. }
  1002. /*!
  1003. \private
  1004. */
  1005. function writeInclude( $element )
  1006. {
  1007. $includeFile = $element[1];
  1008. $includeType = $element[2];
  1009. $parameters = $element[3];
  1010. if ( $includeType == eZPHPCreator::INCLUDE_ONCE_STATEMENT )
  1011. $includeName = 'include_once';
  1012. else if ( $includeType == eZPHPCreator::INCLUDE_ALWAYS_STATEMENT )
  1013. $includeName = 'include';
  1014. $includeFileText = $this->thisVariableText( $includeFile, 0 );
  1015. $text = "$includeName( $includeFileText );\n";
  1016. if ( $this->Spacing )
  1017. {
  1018. $spacing = 0;
  1019. if ( isset( $parameters['spacing'] ) )
  1020. $spacing = $parameters['spacing'];
  1021. $text = str_repeat( ' ', $spacing ) . $text;
  1022. }
  1023. $this->write( $text );
  1024. }
  1025. /*!
  1026. \private
  1027. */
  1028. function writeComment( $element )
  1029. {
  1030. $elementAttributes = $element[2];
  1031. $spacing = 0;
  1032. if ( isset( $elementAttributes['spacing'] ) and $this->Spacing )
  1033. $spacing = $elementAttributes['spacing'];
  1034. $whitespaceHandling = $elementAttributes['whitespace-handling'];
  1035. $eol = $elementAttributes['eol'];
  1036. $newCommentArray = array();
  1037. $commentArray = preg_split( "/\r\n|\r|\n/", $element[1] );
  1038. foreach ( $commentArray as $comment )
  1039. {
  1040. $textLine = '// ' . $comment;
  1041. if ( $whitespaceHandling )
  1042. {
  1043. $textLine = rtrim( $textLine );
  1044. $textLine = str_replace( "\t", ' ', $textLine );
  1045. }
  1046. $textLine = str_repeat( ' ', $spacing ) . $textLine;
  1047. $newCommentArray[] = $textLine;
  1048. }
  1049. $text = implode( "\n", $newCommentArray );
  1050. if ( $eol )
  1051. $text .= "\n";
  1052. $this->write( $text );
  1053. }
  1054. /*!
  1055. \private
  1056. */
  1057. function writeSpace( $element )
  1058. {
  1059. $text = str_repeat( "\n", $element[1] );
  1060. $this->write( $text );
  1061. }
  1062. /*!
  1063. \private
  1064. */
  1065. function writeCodePiece( $element )
  1066. {
  1067. $code = $element[1];
  1068. $parameters = $element[2];
  1069. $spacing = 0;
  1070. if ( isset( $parameters['spacing'] ) and $this->Spacing )
  1071. $spacing = $parameters['spacing'];
  1072. $text = eZPHPCreator::prependSpacing( $code, $spacing );
  1073. $this->write( $text );
  1074. }
  1075. /*!
  1076. \private
  1077. */
  1078. function writeText( $element )
  1079. {
  1080. $text = $element[1];
  1081. $this->write( "\n?>" );
  1082. $this->write( $text );
  1083. $this->write( "<?php\n" );
  1084. }
  1085. /*!
  1086. \private
  1087. */
  1088. function writeMethodCall( $element )
  1089. {
  1090. $objectName = $element[1];
  1091. $methodName = $element[2];
  1092. $methodParameters = $element[3];
  1093. $returnValue = $element[4];
  1094. $parameters = $element[5];
  1095. $text = '';
  1096. $spacing = 0;
  1097. if ( isset( $parameters['spacing'] ) and $this->Spacing )
  1098. $spacing = $parameters['spacing'];
  1099. if ( is_array( $returnValue ) )
  1100. {
  1101. $variableName = $returnValue[0];
  1102. $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT;
  1103. if ( isset( $variableValue[1] ) )
  1104. $assignmentType = $variableValue[1];
  1105. $text = $this->variableNameText( $variableName, $assignmentType );
  1106. }
  1107. $text .= '$' . $objectName . '->' . $methodName . '(';
  1108. $column = strlen( $text );
  1109. $i = 0;
  1110. foreach ( $methodParameters as $parameterData )
  1111. {
  1112. if ( $i > 0 )
  1113. $text .= ",\n" . str_repeat( ' ', $column );
  1114. $parameterType = eZPHPCreator::METHOD_CALL_PARAMETER_VALUE;
  1115. $parameterValue = $parameterData[0];
  1116. if ( isset( $parameterData[1] ) )
  1117. $parameterType = $parameterData[1];
  1118. if ( $parameterType == eZPHPCreator::METHOD_CALL_PARAMETER_VALUE )
  1119. $text .= ' ' . $this->thisVariableText( $parameterValue, $column + 1 );
  1120. else if ( $parameterType == eZPHPCreator::METHOD_CALL_PARAMETER_VARIABLE )
  1121. $text .= ' $' . $parameterValue;
  1122. ++$i;
  1123. }
  1124. if ( $i > 0 )
  1125. $text .= ' ';
  1126. $text .= ");\n";
  1127. $text = eZPHPCreator::prependSpacing( $text, $spacing );
  1128. $this->write( $text );
  1129. }
  1130. /*!
  1131. \private
  1132. */
  1133. function writeVariableUnset( $element )
  1134. {
  1135. $variableName = $element[1];
  1136. $parameters = $element[2];
  1137. $spacing = 0;
  1138. if ( isset( $parameters['spacing'] ) and $this->Spacing )
  1139. $spacing = $parameters['spacing'];
  1140. $text = "unset( \$$variableName );\n";
  1141. $text = eZPHPCreator::prependSpacing( $text, $spacing );
  1142. $this->write( $text );
  1143. }
  1144. /*!
  1145. \private
  1146. */
  1147. function writeVariableUnsetList( $element )
  1148. {
  1149. $variableNames = $element[1];
  1150. if ( count( $variableNames ) )
  1151. {
  1152. $parameters = $element[2];
  1153. $spacing = 0;
  1154. if ( isset( $parameters['spacing'] ) and $this->Spacing )
  1155. $spacing = $parameters['spacing'];
  1156. $text = 'unset( ';
  1157. array_walk( $variableNames, create_function( '&$variableName,$key', '$variableName = "\$" . $variableName;') );
  1158. $text .= join( ', ', $variableNames );
  1159. $text .= " );\n";
  1160. $text = eZPHPCreator::prependSpacing( $text, $spacing );
  1161. $this->write( $text );
  1162. }
  1163. }
  1164. /*!
  1165. \private
  1166. */
  1167. function writeRawVariable( $variableName, $variableValue )
  1168. {
  1169. $this->write( "\${$variableName} = ". var_export( $variableValue, true). ";\n" );
  1170. }
  1171. /*!
  1172. \private
  1173. */
  1174. function writeVariable( $variableName, $variableValue, $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT,
  1175. $variableParameters = array() )
  1176. {
  1177. $variableParameters = array_merge( array( 'full-tree' => false,
  1178. 'spacing' => 0 ),
  1179. $variableParameters );
  1180. $fullTree = $variableParameters['full-tree'];
  1181. $spacing = $this->Spacing ? $variableParameters['spacing'] : 0;
  1182. $text = $this->variableNameText( $variableName, $assignmentType, $variableParameters );
  1183. $maxIterations = 2;
  1184. if ( $fullTree )
  1185. $maxIterations = false;
  1186. $text .= $this->thisVariableText( $variableValue, strlen( $text ), 0, $maxIterations );
  1187. $text .= ";\n";
  1188. $text = eZPHPCreator::prependSpacing( $text, $spacing );
  1189. $this->write( $text );
  1190. }
  1191. /*!
  1192. \private
  1193. */
  1194. function temporaryVariableName( $prefix )
  1195. {
  1196. $variableName = $prefix . '_' . $this->TemporaryCounter;
  1197. ++$this->TemporaryCounter;
  1198. return $variableName;
  1199. }
  1200. /// \privatesection
  1201. public $PHPDir;
  1202. public $PHPFile;
  1203. public $FileResource;
  1204. public $Elements;
  1205. public $TextChunks;
  1206. public $isAtomic;
  1207. public $tmpFilename;
  1208. public $requestedFilename;
  1209. public $Spacing = true;
  1210. public $ClusteringEnabled = false;
  1211. public $ClusterFileScope = false;
  1212. }
  1213. ?>