|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZPHPCreator class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /*! 00012 \class eZPHPCreator ezphpcreator.php 00013 \ingroup eZUtils 00014 \brief eZPHPCreator provides a simple interface for creating and executing PHP code. 00015 00016 To create PHP code you must create an instance of this class, 00017 add any number of elements you choose with 00018 addDefine(), addVariable(), addVariableUnset(), addVariableUnsetList(), 00019 addSpace(), addText(), addMethodCall(), addCodePiece(), addComment() and 00020 addInclude(). 00021 After that you call store() to write all changes to disk. 00022 00023 \code 00024 $php = new eZPHPCreator( 'cache', 'code.php' ); 00025 00026 $php->addComment( 'Auto generated' ); 00027 $php->addInclude( 'inc.php' ); 00028 $php->addVariable( 'count', 10 ); 00029 00030 $php->store(); 00031 \endcode 00032 00033 To restore PHP code you must create an instance of this class, 00034 check if you can restore it with canRestore() then restore variables with restore(). 00035 The class will include PHP file and run all code, once the file is done it will 00036 catch any variables you require and return it to you. 00037 00038 \code 00039 $php = new eZPHPCreator( 'cache', 'code.php' ); 00040 00041 if ( $php->canRestore() ) 00042 { 00043 $variables = $php->restore( array( 'max_count' => 'count' ) ); 00044 print( "Max count was " . $variables['max_count'] ); 00045 } 00046 00047 $php->close(); 00048 \endcode 00049 00050 */ 00051 00052 class eZPHPCreator 00053 { 00054 const VARIABLE = 1; 00055 const SPACE = 2; 00056 const TEXT = 3; 00057 const METHOD_CALL = 4; 00058 const CODE_PIECE = 5; 00059 const EOL_COMMENT = 6; 00060 const INCLUDE_STATEMENT = 7; 00061 const VARIABLE_UNSET = 8; 00062 const DEFINE = 9; 00063 const VARIABLE_UNSET_LIST = 10; 00064 const RAW_VARIABLE = 11; 00065 00066 const VARIABLE_ASSIGNMENT = 1; 00067 const VARIABLE_APPEND_TEXT = 2; 00068 const VARIABLE_APPEND_ELEMENT = 3; 00069 00070 const INCLUDE_ONCE_STATEMENT = 1; 00071 const INCLUDE_ALWAYS_STATEMENT = 2; 00072 00073 const METHOD_CALL_PARAMETER_VALUE = 1; 00074 const METHOD_CALL_PARAMETER_VARIABLE = 2; 00075 00076 /*! 00077 Initializes the creator with the directory path \a $dir and filename \a $file. 00078 */ 00079 function eZPHPCreator( $dir, $file, $prefix = '', $options = array() ) 00080 { 00081 $this->PHPDir = $dir; 00082 $this->PHPFile = $file; 00083 $this->FilePrefix = $prefix; 00084 $this->FileResource = false; 00085 $this->Elements = array(); 00086 $this->TextChunks = array(); 00087 $this->TemporaryCounter = 0; 00088 if ( isset( $options['spacing'] ) and ( $options['spacing'] == 'disabled') ) 00089 { 00090 $this->Spacing = false; 00091 } 00092 else 00093 { 00094 $this->Spacing = true; 00095 } 00096 00097 if ( isset( $options['clustering'] ) ) 00098 { 00099 $this->ClusteringEnabled = true; 00100 $this->ClusterFileScope = $options['clustering']; 00101 } 00102 else 00103 { 00104 $this->ClusteringEnabled = false; 00105 } 00106 $this->ClusterHandler = null; 00107 } 00108 00109 //@{ 00110 00111 /*! 00112 Adds a new define statement to the code with the name \a $name and value \a $value. 00113 The parameter \a $caseSensitive determines if the define should be made case sensitive or not. 00114 00115 Example: 00116 \code 00117 $php->addDefine( 'MY_CONSTANT', 5 ); 00118 \endcode 00119 00120 Would result in the PHP code. 00121 00122 \code 00123 define( 'MY_CONSTANT', 5 ); 00124 \endcode 00125 00126 \param $parameters Optional parameters, can be any of the following: 00127 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00128 00129 \note \a $name must start with a letter or underscore, followed by any number of letters, numbers, or underscores. 00130 See http://php.net/manual/en/language.constants.php for more information. 00131 \sa http://php.net/manual/en/function.define.php 00132 */ 00133 function addDefine( $name, $value, $caseSensitive = true, $parameters = array() ) 00134 { 00135 $element = array( eZPHPCreator::DEFINE, 00136 $name, 00137 $value, 00138 $caseSensitive, 00139 $parameters ); 00140 $this->Elements[] = $element; 00141 } 00142 00143 /*! 00144 Adds a new raw variable tothe code with the name \a $name and value \a $value. 00145 00146 Example: 00147 \code 00148 $php->addVariable( 'TransLationRoot', $cache['root'] ); 00149 \endcode 00150 00151 This function makes use of PHP's var_export() function which is optimized 00152 for this task. 00153 */ 00154 function addRawVariable( $name, $value ) 00155 { 00156 $element = array( eZPHPCreator::RAW_VARIABLE, $name, $value ); 00157 $this->Elements[] = $element; 00158 } 00159 00160 /*! 00161 Adds a new variable to the code with the name \a $name and value \a $value. 00162 00163 Example: 00164 \code 00165 $php->addVariable( 'offset', 5 ); 00166 $php->addVariable( 'text', 'some more text', eZPHPCreator::VARIABLE_APPEND_TEXT ); 00167 $php->addVariable( 'array', 42, eZPHPCreator::VARIABLE_APPEND_ELEMENT ); 00168 \endcode 00169 00170 Would result in the PHP code. 00171 00172 \code 00173 $offset = 5; 00174 $text .= 'some more text'; 00175 $array[] = 42; 00176 \endcode 00177 00178 \param $assignmentType Controls the way the value is assigned, choose one of the following: 00179 - \b eZPHPCreator::VARIABLE_ASSIGNMENT, assign using \c = (default) 00180 - \b eZPHPCreator::VARIABLE_APPEND_TEXT, append using text concat operator \c . 00181 - \b eZPHPCreator::VARIABLE_APPEND_ELEMENT, append element to array using append operator \c [] 00182 \param $parameters Optional parameters, can be any of the following: 00183 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00184 - \a full-tree, Whether to displays array values as one large expression (\c true) or 00185 split it up into multiple variables (\c false) 00186 00187 */ 00188 function addVariable( $name, $value, $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT, 00189 $parameters = array() ) 00190 { 00191 $element = array( eZPHPCreator::VARIABLE, 00192 $name, 00193 $value, 00194 $assignmentType, 00195 $parameters ); 00196 $this->Elements[] = $element; 00197 } 00198 00199 /*! 00200 Adds code to unset a variable with the name \a $name. 00201 00202 Example: 00203 \code 00204 $php->addVariableUnset( 'offset' ); 00205 \endcode 00206 00207 Would result in the PHP code. 00208 00209 \code 00210 unset( $offset ); 00211 \endcode 00212 00213 \param $parameters Optional parameters, can be any of the following: 00214 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00215 00216 \sa http://php.net/manual/en/function.unset.php 00217 */ 00218 function addVariableUnset( $name, 00219 $parameters = array() ) 00220 { 00221 $element = array( eZPHPCreator::VARIABLE_UNSET, 00222 $name, 00223 $parameters ); 00224 $this->Elements[] = $element; 00225 } 00226 00227 /*! 00228 Adds code to unset a list of variables with name from \a $list. 00229 00230 Example: 00231 \code 00232 $php->addVariableUnsetList( array ( 'var1', 'var2' ) ); 00233 \endcode 00234 00235 Would result in the PHP code. 00236 00237 \code 00238 unset( $var1, $var2 ); 00239 \endcode 00240 00241 \param $parameters Optional parameters, can be any of the following: 00242 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00243 00244 \sa http://php.net/manual/en/function.unset.php 00245 */ 00246 function addVariableUnsetList( $list, 00247 $parameters = array() ) 00248 { 00249 $element = array( eZPHPCreator::VARIABLE_UNSET_LIST, 00250 $list, 00251 $parameters ); 00252 $this->Elements[] = $element; 00253 } 00254 00255 /*! 00256 Adds some space to the code in form of newlines. The number of lines 00257 is controlled with \a $lines which is \c 1 by default. 00258 You can use this to get more readable PHP code. 00259 00260 Example: 00261 \code 00262 $php->addSpace( 1 ); 00263 \endcode 00264 */ 00265 function addSpace( $lines = 1 ) 00266 { 00267 $element = array( eZPHPCreator::SPACE, 00268 $lines ); 00269 $this->Elements[] = $element; 00270 } 00271 00272 /*! 00273 Adds some plain text to the code. The text will be placed 00274 outside of PHP start and end markers and will in principle 00275 work as printing the text. 00276 00277 Example: 00278 \code 00279 $php->addText( 'Print me!' ); 00280 \endcode 00281 */ 00282 function addText( $text ) 00283 { 00284 $element = array( eZPHPCreator::TEXT, 00285 $text ); 00286 $this->Elements[] = $element; 00287 } 00288 00289 /*! 00290 Adds code to call the method \a $methodName on the object named \a $objectName, 00291 \a $methodParameters should be an array with parameter entries where each entry contains: 00292 - \a 0, The parameter value 00293 - \a 1 (\em optional), The type of parameter, is one of: 00294 - \b eZPHPCreator::METHOD_CALL_PARAMETER_VALUE, Use value directly (default if this entry is missing) 00295 - \b eZPHPCreator::METHOD_CALL_PARAMETER_VARIABLE, Use value as the name of the variable. 00296 00297 Optionally the \a $returnValue parameter can be used to decide what should be done 00298 with the return value of the method call. It can either be \c false which means 00299 to do nothing or an array with the following entries. 00300 - \a 0, The name of the variable to assign the value to 00301 - \a 1 (\em optional), The type of assignment, uses the same value as addVariable(). 00302 00303 \param $parameters Optional parameters, can be any of the following: 00304 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00305 00306 Example: 00307 \code 00308 $php->addMethodCall( 'node', 'name', array(), array( 'name' ) ); 00309 $php->addMethodCall( 'php', 'addMethodCall', 00310 array( array( 'node' ), array( 'name' ) ) ); 00311 \endcode 00312 00313 Would result in the PHP code. 00314 00315 \code 00316 $name = $node->name(); 00317 $php->addMethodCall( 'node', 'name' ); 00318 \endcode 00319 */ 00320 function addMethodCall( $objectName, $methodName, $methodParameters, $returnValue = false, $parameters = array() ) 00321 { 00322 $element = array( eZPHPCreator::METHOD_CALL, 00323 $objectName, 00324 $methodName, 00325 $methodParameters, 00326 $returnValue, 00327 $parameters ); 00328 $this->Elements[] = $element; 00329 } 00330 00331 /*! 00332 Adds custom PHP code to the file, you should only use this a last resort if any 00333 of the other \em add functions done give you the required result. 00334 00335 \param $code Contains the code as text, the text will not be modified (except for spacing). 00336 This means that each expression must be ended with a newline even if it's just one. 00337 \param $parameters Optional parameters, can be any of the following: 00338 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00339 00340 Example: 00341 \code 00342 $php->addCodePiece( "if ( \$value > 2 )\n{\n \$value = 2;\n}\n" ); 00343 \endcode 00344 00345 Would result in the PHP code. 00346 00347 \code 00348 if ( $value > 2 ) 00349 { 00350 $value = 2; 00351 } 00352 \endcode 00353 00354 */ 00355 function addCodePiece( $code, $parameters = array() ) 00356 { 00357 $element = array( eZPHPCreator::CODE_PIECE, 00358 $code, 00359 $parameters ); 00360 $this->Elements[] = $element; 00361 } 00362 00363 /*! 00364 Adds a comment to the code, the comment will be display using multiple end-of-line 00365 comments (//), one for each newline in the text \a $comment. 00366 00367 \param $eol Whether to add a newline at the last comment line 00368 \param $whitespaceHandling Whether to remove trailing whitespace from each line 00369 \param $parameters Optional parameters, can be any of the following: 00370 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00371 00372 Example: 00373 \code 00374 $php->addComment( "This file is auto generated\nDo not edit!" ); 00375 \endcode 00376 00377 Would result in the PHP code. 00378 00379 \code 00380 // This file is auto generated 00381 // Do not edit! 00382 \endcode 00383 00384 */ 00385 function addComment( $comment, $eol = true, $whitespaceHandling = true, $parameters = array() ) 00386 { 00387 $element = array( eZPHPCreator::EOL_COMMENT, 00388 $comment, 00389 array_merge( $parameters, 00390 array( 'eol' => $eol, 00391 'whitespace-handling' => $whitespaceHandling ) ) ); 00392 $this->Elements[] = $element; 00393 } 00394 00395 /*! 00396 Adds an include statement to the code, the file to include is \a $file. 00397 00398 \param $type What type of include statement to use, can be one of the following: 00399 - \b eZPHPCreator::INCLUDE_ONCE_STATEMENT, use \em include_once() 00400 - \b eZPHPCreator::INCLUDE_ALWAYS_STATEMENT, use \em include() 00401 \param $parameters Optional parameters, can be any of the following: 00402 - \a spacing, The number of spaces to place before each code line, default is \c 0. 00403 00404 Example: 00405 \code 00406 $php->addInclude( 'lib/ezutils/classes/ezphpcreator.php' ); 00407 \endcode 00408 00409 Would result in the PHP code. 00410 00411 \code 00412 //include_once( 'lib/ezutils/classes/ezphpcreator.php' ); 00413 \endcode 00414 00415 */ 00416 function addInclude( $file, $type = eZPHPCreator::INCLUDE_ONCE_STATEMENT, $parameters = array() ) 00417 { 00418 $element = array( eZPHPCreator::INCLUDE_STATEMENT, 00419 $file, 00420 $type, 00421 $parameters ); 00422 $this->Elements[] = $element; 00423 } 00424 00425 //@} 00426 00427 /*! 00428 \static 00429 Creates a variable statement with an assignment type and returns it. 00430 \param $variableName The name of the variable 00431 \param $assignmentType What kind of assignment to use, is one of the following; 00432 - \b eZPHPCreator::VARIABLE_ASSIGNMENT, assign using \c = 00433 - \b eZPHPCreator::VARIABLE_APPEND_TEXT, append to text using \c . 00434 - \b eZPHPCreator::VARIABLE_APPEND_ELEMENT, append to array using \c [] 00435 \param $variableParameters Optional parameters for the statement 00436 */ 00437 static function variableNameText( $variableName, $assignmentType, $variableParameters = array() ) 00438 { 00439 $text = '$' . $variableName; 00440 if ( $assignmentType == eZPHPCreator::VARIABLE_ASSIGNMENT ) 00441 { 00442 $text .= ' = '; 00443 } 00444 else if ( $assignmentType == eZPHPCreator::VARIABLE_APPEND_TEXT ) 00445 { 00446 $text .= ' .= '; 00447 } 00448 else if ( $assignmentType == eZPHPCreator::VARIABLE_APPEND_ELEMENT ) 00449 { 00450 $text .= '[] = '; 00451 } 00452 return $text; 00453 } 00454 00455 /*! 00456 Creates a text representation of the value \a $value which can 00457 be placed in files and be read back by a PHP parser as it was. 00458 The type of the values determines the output, it can be one of the following. 00459 - boolean, becomes \c true or \c false 00460 - null, becomes \c null 00461 - string, adds \ (backslash) to backslashes, double quotes, dollar signs and newlines. 00462 Then wraps the whole string in " (double quotes). 00463 - numeric, displays the value as-is. 00464 - array, expands all value recursively using this function 00465 - object, creates a representation of an object creation if the object has \c serializeData implemented. 00466 00467 \param $column Determines the starting column in which the text will be placed. 00468 This is used for expanding arrays and objects which can span multiple lines. 00469 \param $iteration The current iteration, starts at 0 and increases with 1 for each recursive call 00470 \param $maxIterations The maximum number of iterations to allow, if the iteration 00471 exceeds this the array or object will be split into multiple variables. 00472 Can be set to \c false to the array or object as-is. 00473 00474 \note This function can be called statically if \a $maxIterations is set to \c false 00475 */ 00476 function thisVariableText( $value, $column = 0, $iteration = 0, $maxIterations = 2 ) 00477 { 00478 if ( isset( $this->Spacing ) and !$this->Spacing ) 00479 { 00480 return var_export( $value, true ); 00481 } 00482 00483 if ( $value === true ) 00484 $text = 'true'; 00485 else if ( $value === false ) 00486 $text = 'false'; 00487 else if ( $value === null ) 00488 $text = 'null'; 00489 else if ( is_string( $value ) ) 00490 { 00491 $valueText = str_replace( array( "\\", 00492 "\"", 00493 "\$", 00494 "\n" ), 00495 array( "\\\\", 00496 "\\\"", 00497 "\\$", 00498 "\\n" ), 00499 $value ); 00500 $text = "\"$valueText\""; 00501 } 00502 else if ( is_numeric( $value ) ) 00503 $text = $value; 00504 else if ( is_object( $value ) ) 00505 { 00506 if ( $maxIterations !== false and 00507 $iteration > $maxIterations ) 00508 { 00509 $temporaryVariableName = $this->temporaryVariableName( 'obj' ); 00510 $this->writeVariable( $temporaryVariableName, $value ); 00511 $text = '$' . $temporaryVariableName; 00512 } 00513 else 00514 { 00515 $text = ''; 00516 if ( method_exists( $value, 'serializeData' ) ) 00517 { 00518 $serializeData = $value->serializeData(); 00519 $className = $serializeData['class_name']; 00520 $text = "new $className("; 00521 00522 $column += strlen( $text ); 00523 $parameters = $serializeData['parameters']; 00524 $variables = $serializeData['variables']; 00525 00526 $i = 0; 00527 foreach ( $parameters as $parameter ) 00528 { 00529 if ( $i > 0 ) 00530 { 00531 $text .= ",\n" . str_repeat( ' ', $column ); 00532 } 00533 $variableName = $variables[$parameter]; 00534 $variableValue = $value->$variableName; 00535 $keyText = " "; 00536 00537 $text .= $keyText . $this->thisVariableText( $variableValue, $column + strlen( $keyText ), $iteration + 1, $maxIterations ); 00538 00539 ++$i; 00540 } 00541 if ( $i > 0 ) 00542 $text .= ' '; 00543 00544 $text .= ')'; 00545 } 00546 } 00547 } 00548 else if ( is_array( $value ) ) 00549 { 00550 if ( $maxIterations !== false and 00551 $iteration > $maxIterations ) 00552 { 00553 $temporaryVariableName = $this->temporaryVariableName( 'arr' ); 00554 $this->writeVariable( $temporaryVariableName, $value ); 00555 $text = '$' . $temporaryVariableName; 00556 } 00557 else 00558 { 00559 $text = 'array('; 00560 $column += strlen( $text ); 00561 $valueKeys = array_keys( $value ); 00562 $isIndexed = true; 00563 for ( $i = 0; $i < count( $valueKeys ); ++$i ) 00564 { 00565 if ( $i !== $valueKeys[$i] ) 00566 { 00567 $isIndexed = false; 00568 break; 00569 } 00570 } 00571 $i = 0; 00572 foreach ( $valueKeys as $key ) 00573 { 00574 if ( $i > 0 ) 00575 { 00576 $text .= ",\n" . str_repeat( ' ', $column ); 00577 } 00578 $element = $value[$key]; 00579 $keyText = ' '; 00580 if ( !$isIndexed ) 00581 { 00582 if ( is_int( $key ) ) 00583 $keyText = $key; 00584 else 00585 $keyText = "\"" . str_replace( array( "\\", 00586 "\"", 00587 "\n" ), 00588 array( "\\\\", 00589 "\\\"", 00590 "\\n" ), 00591 $key ) . "\""; 00592 $keyText = " $keyText => "; 00593 } 00594 00595 $text .= $keyText . $this->thisVariableText( $element, $column + strlen( $keyText ), $iteration + 1, $maxIterations ); 00596 00597 ++$i; 00598 } 00599 if ( $i > 0 ) 00600 $text .= ' '; 00601 $text .= ')'; 00602 } 00603 } 00604 else 00605 $text = 'null'; 00606 return $text; 00607 } 00608 00609 static function variableText( $value, $column = 0, $iteration = 0, $maxIterations = false ) 00610 { 00611 // the last parameter will always be ignored 00612 $maxIterations = false; 00613 00614 if ( $value === true ) 00615 $text = 'true'; 00616 else if ( $value === false ) 00617 $text = 'false'; 00618 else if ( $value === null ) 00619 $text = 'null'; 00620 else if ( is_string( $value ) ) 00621 { 00622 $valueText = str_replace( array( "\\", 00623 "\"", 00624 "\$", 00625 "\n" ), 00626 array( "\\\\", 00627 "\\\"", 00628 "\\$", 00629 "\\n" ), 00630 $value ); 00631 $text = "\"$valueText\""; 00632 } 00633 else if ( is_numeric( $value ) ) 00634 $text = $value; 00635 else if ( is_object( $value ) ) 00636 { 00637 $text = ''; 00638 if ( method_exists( $value, 'serializeData' ) ) 00639 { 00640 $serializeData = $value->serializeData(); 00641 $className = $serializeData['class_name']; 00642 $text = "new $className("; 00643 00644 $column += strlen( $text ); 00645 $parameters = $serializeData['parameters']; 00646 $variables = $serializeData['variables']; 00647 00648 $i = 0; 00649 foreach ( $parameters as $parameter ) 00650 { 00651 if ( $i > 0 ) 00652 { 00653 $text .= ",\n" . str_repeat( ' ', $column ); 00654 } 00655 $variableName = $variables[$parameter]; 00656 $variableValue = $value->$variableName; 00657 $keyText = " "; 00658 00659 $text .= $keyText . eZPHPCreator::variableText( $variableValue, $column + strlen( $keyText ), $iteration + 1 ); 00660 ++$i; 00661 } 00662 if ( $i > 0 ) 00663 $text .= ' '; 00664 00665 $text .= ')'; 00666 } 00667 } 00668 else if ( is_array( $value ) ) 00669 { 00670 $text = 'array('; 00671 $column += strlen( $text ); 00672 $valueKeys = array_keys( $value ); 00673 $isIndexed = true; 00674 for ( $i = 0; $i < count( $valueKeys ); ++$i ) 00675 { 00676 if ( $i !== $valueKeys[$i] ) 00677 { 00678 $isIndexed = false; 00679 break; 00680 } 00681 } 00682 $i = 0; 00683 foreach ( $valueKeys as $key ) 00684 { 00685 if ( $i > 0 ) 00686 { 00687 $text .= ",\n" . str_repeat( ' ', $column ); 00688 } 00689 $element = $value[$key]; 00690 $keyText = ' '; 00691 if ( !$isIndexed ) 00692 { 00693 if ( is_int( $key ) ) 00694 $keyText = $key; 00695 else 00696 $keyText = "\"" . str_replace( array( "\\", 00697 "\"", 00698 "\n" ), 00699 array( "\\\\", 00700 "\\\"", 00701 "\\n" ), 00702 $key ) . "\""; 00703 $keyText = " $keyText => "; 00704 } 00705 00706 $text .= $keyText . eZPHPCreator::variableText( $element, $column + strlen( $keyText ), $iteration + 1 ); 00707 00708 ++$i; 00709 } 00710 if ( $i > 0 ) 00711 $text .= ' '; 00712 $text .= ')'; 00713 } 00714 else 00715 $text = 'null'; 00716 return $text; 00717 } 00718 00719 /*! 00720 \static 00721 Splits \a $text into multiple lines using \a $splitString for splitting. 00722 For each line it will prepend the string \a $spacingString n times as specified by \a $spacing. 00723 00724 It will try to be smart and not do anything when \a $spacing is set to \c 0. 00725 00726 \param $skipEmptyLines If \c true it will not prepend the string for empty lines. 00727 \param $spacing Must be a positive number, \c 0 means to not prepend anything. 00728 */ 00729 static function prependSpacing( $text, $spacing, $skipEmptyLines = true, $spacingString = " ", $splitString = "\n" ) 00730 { 00731 if ( $spacing == 0 ) 00732 return $text; 00733 $textArray = explode( $splitString, $text ); 00734 $newTextArray = array(); 00735 foreach ( $textArray as $text ) 00736 { 00737 if ( trim( $text ) != '' ) 00738 $textLine = str_repeat( $spacingString, $spacing ) . $text; 00739 else 00740 $textLine = $text; 00741 $newTextArray[] = $textLine; 00742 } 00743 return implode( $splitString, $newTextArray ); 00744 } 00745 00746 //@{ 00747 00748 /*! 00749 Opens the file for writing and sets correct file permissions. 00750 \return The current file resource or \c false if it failed to open the file. 00751 \note The file name and path is supplied to the constructor of this class. 00752 \note Multiple calls to this method will only open the file once. 00753 */ 00754 function open( $atomic = false ) 00755 { 00756 if ( $this->ClusteringEnabled ) 00757 return true; 00758 00759 if ( !$this->FileResource ) 00760 { 00761 if ( !file_exists( $this->PHPDir ) ) 00762 { 00763 eZDir::mkdir( $this->PHPDir, false, true ); 00764 } 00765 $path = $this->PHPDir . '/' . $this->PHPFile; 00766 $oldumask = umask( 0 ); 00767 $pathExisted = file_exists( $path ); 00768 if ( $atomic ) 00769 { 00770 $this->isAtomic = true; 00771 $this->requestedFilename = $path; 00772 $uniqid = md5( uniqid( "ezp". getmypid(), true ) ); 00773 $path .= ".$uniqid"; 00774 $this->tmpFilename = $path; 00775 } 00776 $ini = eZINI::instance(); 00777 $perm = octdec( $ini->variable( 'FileSettings', 'StorageFilePermissions' ) ); 00778 $this->FileResource = @fopen( $this->FilePrefix . $path, "w" ); 00779 if ( !$this->FileResource ) 00780 eZDebug::writeError( "Could not open file '$path' for writing, perhaps wrong permissions" ); 00781 if ( $this->FileResource and 00782 !$pathExisted ) 00783 chmod( $path, $perm ); 00784 umask( $oldumask ); 00785 } 00786 return $this->FileResource; 00787 } 00788 00789 /*! 00790 Closes the currently open file if any. 00791 */ 00792 function close() 00793 { 00794 if ( $this->ClusteringEnabled ) 00795 { 00796 $this->ClusterHandler = null; 00797 return; 00798 } 00799 00800 if ( $this->FileResource ) 00801 { 00802 fclose( $this->FileResource ); 00803 00804 if ( $this->isAtomic ) 00805 { 00806 eZFile::rename( $this->tmpFilename, $this->requestedFilename, false, eZFile::CLEAN_ON_FAILURE ); 00807 } 00808 $this->FileResource = false; 00809 } 00810 } 00811 00812 /*! 00813 \return \c true if the file and path already exists. 00814 \note The file name and path is supplied to the constructor of this class. 00815 */ 00816 function exists() 00817 { 00818 $path = $this->PHPDir . '/' . $this->PHPFile; 00819 if ( !$this->ClusteringEnabled ) 00820 return file_exists( $path ); 00821 00822 if ( !$this->ClusterHandler ) 00823 { 00824 $this->ClusterHandler = eZClusterFileHandler::instance(); 00825 } 00826 return $this->ClusterHandler->fileExists( $path ); 00827 } 00828 00829 /*! 00830 \return \c true if file exists and can be restored. 00831 \param $timestamp The timestamp to check the modification time of the file against, 00832 if the modification time is larger or equal to \a $timestamp 00833 the file can be restored. Otherwise the file is considered too old. 00834 \note The file name and path is supplied to the constructor of this class. 00835 */ 00836 function canRestore( $timestamp = false ) 00837 { 00838 $path = $this->PHPDir . '/' . $this->PHPFile; 00839 00840 if ( $this->ClusteringEnabled ) 00841 { 00842 if ( !$this->ClusterHandler ) 00843 { 00844 $this->ClusterHandler = eZClusterFileHandler::instance( $path ); 00845 } 00846 // isExpired() expects -1 to disable expiry check 00847 $expiry = ( $timestamp === false ) ? -1 : $timestamp; 00848 return !$this->ClusterHandler->isExpired( $expiry, time(), null ); 00849 } 00850 00851 $canRestore = file_exists( $path ); 00852 if ( $timestamp !== false and 00853 $canRestore ) 00854 { 00855 $cacheModifierTime = filemtime( $path ); 00856 $canRestore = ( $cacheModifierTime >= $timestamp ); 00857 } 00858 00859 return $canRestore; 00860 } 00861 00862 /*! 00863 Tries to restore the PHP file and fetch the defined variables in \a $variableDefinitions. 00864 This basically means including the file using include(). 00865 00866 \param $variableDefinitions Associative array with the return variable name being the key 00867 matched variable as value. 00868 00869 \return An associatve array with the variables that were found according to \a $variableDefinitions. 00870 00871 Example: 00872 \code 00873 $values = $php->restore( array( 'MyValue' => 'node' ) ); 00874 print( $values['MyValue'] ); 00875 \endcode 00876 00877 \note The file name and path is supplied to the constructor of this class. 00878 */ 00879 function restore( $variableDefinitions ) 00880 { 00881 $returnVariables = array(); 00882 $path = $this->PHPDir . '/' . $this->PHPFile; 00883 00884 if ( !$this->ClusteringEnabled ) 00885 { 00886 $returnVariables = $this->_restoreCall( $path, false, $variableDefinitions ); 00887 } 00888 else 00889 { 00890 if ( !$this->ClusterHandler ) 00891 { 00892 $this->ClusterHandler = eZClusterFileHandler::instance( $path ); 00893 } 00894 $returnVariables = $this->ClusterHandler->processFile( array( $this, '_restoreCall' ), null, $variableDefinitions ); 00895 } 00896 return $returnVariables; 00897 } 00898 00899 /*! 00900 \private 00901 Processes the PHP file and returns the specified data. 00902 */ 00903 function _restoreCall( $path, $mtime, $variableDefinitions ) 00904 { 00905 $returnVariables = array(); 00906 include( $path ); 00907 foreach ( $variableDefinitions as $variableReturnName => $variableName ) 00908 { 00909 $variableRequired = true; 00910 $variableDefault = false; 00911 if ( is_array( $variableName ) ) 00912 { 00913 $variableDefinition = $variableName; 00914 $variableName = $variableDefinition['name']; 00915 $variableRequired = $variableDefinition['required']; 00916 if ( isset( $variableDefinition['default'] ) ) 00917 $variableDefault = $variableDefinition['default']; 00918 } 00919 if ( isset( $$variableName ) ) 00920 { 00921 $returnVariables[$variableReturnName] = $$variableName; 00922 } 00923 else if ( $variableRequired ) 00924 { 00925 eZDebug::writeError( "Variable '$variableName' is not present in cache '$path'", __METHOD__ ); 00926 } 00927 else 00928 { 00929 $returnVariables[$variableReturnName] = $variableDefault; 00930 } 00931 } 00932 return $returnVariables; 00933 } 00934 00935 /*! 00936 Stores the PHP cache, returns false if the cache file could not be created. 00937 */ 00938 function store( $atomic = false ) 00939 { 00940 if ( $this->open( $atomic ) ) 00941 { 00942 $this->write( "<?php\n" ); 00943 00944 $this->writeElements(); 00945 00946 $this->write( "?>\n" ); 00947 00948 $this->writeChunks(); 00949 $this->flushChunks(); 00950 $this->close(); 00951 00952 if ( !$this->ClusteringEnabled ) 00953 { 00954 $perm = octdec( eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ) ); 00955 chmod( eZDir::path( array( $this->PHPDir, $this->PHPFile ) ), $perm ); 00956 } 00957 00958 // Write log message to storage.log 00959 eZLog::writeStorageLog( $this->PHPFile, $this->PHPDir . '/' ); 00960 return true; 00961 } 00962 else 00963 { 00964 eZDebug::writeError( "Failed to open file '" . $this->PHPDir . '/' . $this->PHPFile . "'", __METHOD__ ); 00965 return false; 00966 } 00967 } 00968 00969 /*! 00970 Creates a text string out of all elements and returns it. 00971 \note Calling this multiple times will resulting text processing each time. 00972 */ 00973 function fetch( $addPHPMarkers = true ) 00974 { 00975 if ( $addPHPMarkers ) 00976 $this->write( "<?php\n" ); 00977 $this->writeElements(); 00978 if ( $addPHPMarkers ) 00979 $this->write( "?>\n" ); 00980 00981 $text = implode( '', $this->TextChunks ); 00982 00983 $this->flushChunks(); 00984 00985 return $text; 00986 } 00987 00988 //@} 00989 00990 /*! 00991 \private 00992 */ 00993 function writeChunks() 00994 { 00995 $count = count( $this->TextChunks ); 00996 00997 if ( $this->ClusteringEnabled ) 00998 { 00999 $text = ''; 01000 for ( $i = 0; $i < $count; ++$i ) 01001 $text .= $this->TextChunks[$i]; 01002 01003 $filePath = $this->FilePrefix . $this->PHPDir . '/' . $this->PHPFile; 01004 01005 if ( !$this->ClusterHandler ) 01006 { 01007 $this->ClusterHandler = eZClusterFileHandler::instance(); 01008 } 01009 $this->ClusterHandler->fileStoreContents( $filePath, $text, $this->ClusterFileScope, 'php' ); 01010 01011 return; 01012 } 01013 01014 for ( $i = 0; $i < $count; ++$i ) 01015 { 01016 $text = $this->TextChunks[$i]; 01017 fwrite( $this->FileResource, $text ); 01018 } 01019 } 01020 01021 /*! 01022 \private 01023 */ 01024 function flushChunks() 01025 { 01026 $this->TextChunks = array(); 01027 } 01028 01029 /*! 01030 \private 01031 */ 01032 function write( $text ) 01033 { 01034 $this->TextChunks[] = $text; 01035 } 01036 01037 /*! 01038 \private 01039 */ 01040 function writeElements() 01041 { 01042 foreach( $this->Elements as $element ) 01043 { 01044 if ( $element[0] == eZPHPCreator::DEFINE ) 01045 { 01046 $this->writeDefine( $element ); 01047 } 01048 else if ( $element[0] == eZPHPCreator::RAW_VARIABLE ) 01049 { 01050 $this->writeRawVariable( $element[1], $element[2] ); 01051 } 01052 else if ( $element[0] == eZPHPCreator::VARIABLE ) 01053 { 01054 $this->writeVariable( $element[1], $element[2], $element[3], $element[4] ); 01055 } 01056 else if ( $element[0] == eZPHPCreator::VARIABLE_UNSET ) 01057 { 01058 $this->writeVariableUnset( $element ); 01059 } 01060 else if ( $element[0] == eZPHPCreator::VARIABLE_UNSET_LIST ) 01061 { 01062 $this->writeVariableUnsetList( $element ); 01063 } 01064 else if ( $element[0] == eZPHPCreator::SPACE ) 01065 { 01066 $this->writeSpace( $element ); 01067 } 01068 else if ( $element[0] == eZPHPCreator::TEXT ) 01069 { 01070 $this->writeText( $element ); 01071 } 01072 else if ( $element[0] == eZPHPCreator::METHOD_CALL ) 01073 { 01074 $this->writeMethodCall( $element ); 01075 } 01076 else if ( $element[0] == eZPHPCreator::CODE_PIECE ) 01077 { 01078 $this->writeCodePiece( $element ); 01079 } 01080 else if ( $element[0] == eZPHPCreator::EOL_COMMENT ) 01081 { 01082 $this->writeComment( $element ); 01083 } 01084 else if ( $element[0] == eZPHPCreator::INCLUDE_STATEMENT ) 01085 { 01086 $this->writeInclude( $element ); 01087 } 01088 } 01089 } 01090 01091 /*! 01092 \private 01093 */ 01094 function writeDefine( $element ) 01095 { 01096 $name = $element[1]; 01097 $value = $element[2]; 01098 $caseSensitive = $element[3]; 01099 $parameters = $element[4]; 01100 $text = ''; 01101 if ( $this->Spacing ) 01102 { 01103 $spacing = 0; 01104 if ( isset( $parameters['spacing'] ) ) 01105 $spacing = $parameters['spacing']; 01106 $text = str_repeat( ' ', $spacing ); 01107 } 01108 $nameText = $this->thisVariableText( $name, 0 ); 01109 $valueText = $this->thisVariableText( $value, 0 ); 01110 $text .= "define( $nameText, $valueText"; 01111 if ( !$caseSensitive ) 01112 $text .= ", true"; 01113 $text .= " );\n"; 01114 $this->write( $text ); 01115 } 01116 01117 /*! 01118 \private 01119 */ 01120 function writeInclude( $element ) 01121 { 01122 $includeFile = $element[1]; 01123 $includeType = $element[2]; 01124 $parameters = $element[3]; 01125 if ( $includeType == eZPHPCreator::INCLUDE_ONCE_STATEMENT ) 01126 $includeName = 'include_once'; 01127 else if ( $includeType == eZPHPCreator::INCLUDE_ALWAYS_STATEMENT ) 01128 $includeName = 'include'; 01129 $includeFileText = $this->thisVariableText( $includeFile, 0 ); 01130 $text = "$includeName( $includeFileText );\n"; 01131 if ( $this->Spacing ) 01132 { 01133 $spacing = 0; 01134 if ( isset( $parameters['spacing'] ) ) 01135 $spacing = $parameters['spacing']; 01136 $text = str_repeat( ' ', $spacing ) . $text; 01137 } 01138 $this->write( $text ); 01139 } 01140 01141 /*! 01142 \private 01143 */ 01144 function writeComment( $element ) 01145 { 01146 $elementAttributes = $element[2]; 01147 $spacing = 0; 01148 if ( isset( $elementAttributes['spacing'] ) and $this->Spacing ) 01149 $spacing = $elementAttributes['spacing']; 01150 $whitespaceHandling = $elementAttributes['whitespace-handling']; 01151 $eol = $elementAttributes['eol']; 01152 $newCommentArray = array(); 01153 $commentArray = preg_split( "/\r\n|\r|\n/", $element[1] ); 01154 foreach ( $commentArray as $comment ) 01155 { 01156 $textLine = '// ' . $comment; 01157 if ( $whitespaceHandling ) 01158 { 01159 $textLine = rtrim( $textLine ); 01160 $textLine = str_replace( "\t", ' ', $textLine ); 01161 } 01162 $textLine = str_repeat( ' ', $spacing ) . $textLine; 01163 $newCommentArray[] = $textLine; 01164 } 01165 $text = implode( "\n", $newCommentArray ); 01166 if ( $eol ) 01167 $text .= "\n"; 01168 $this->write( $text ); 01169 } 01170 01171 /*! 01172 \private 01173 */ 01174 function writeSpace( $element ) 01175 { 01176 $text = str_repeat( "\n", $element[1] ); 01177 $this->write( $text ); 01178 } 01179 01180 /*! 01181 \private 01182 */ 01183 function writeCodePiece( $element ) 01184 { 01185 $code = $element[1]; 01186 $parameters = $element[2]; 01187 $spacing = 0; 01188 if ( isset( $parameters['spacing'] ) and $this->Spacing ) 01189 $spacing = $parameters['spacing']; 01190 $text = eZPHPCreator::prependSpacing( $code, $spacing ); 01191 $this->write( $text ); 01192 } 01193 01194 /*! 01195 \private 01196 */ 01197 function writeText( $element ) 01198 { 01199 $text = $element[1]; 01200 $this->write( "\n?>" ); 01201 $this->write( $text ); 01202 $this->write( "<?php\n" ); 01203 } 01204 01205 /*! 01206 \private 01207 */ 01208 function writeMethodCall( $element ) 01209 { 01210 $objectName = $element[1]; 01211 $methodName = $element[2]; 01212 $methodParameters = $element[3]; 01213 $returnValue = $element[4]; 01214 $parameters = $element[5]; 01215 $text = ''; 01216 $spacing = 0; 01217 if ( isset( $parameters['spacing'] ) and $this->Spacing ) 01218 $spacing = $parameters['spacing']; 01219 if ( is_array( $returnValue ) ) 01220 { 01221 $variableName = $returnValue[0]; 01222 $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT; 01223 if ( isset( $variableValue[1] ) ) 01224 $assignmentType = $variableValue[1]; 01225 $text = $this->variableNameText( $variableName, $assignmentType ); 01226 } 01227 $text .= '$' . $objectName . '->' . $methodName . '('; 01228 $column = strlen( $text ); 01229 $i = 0; 01230 foreach ( $methodParameters as $parameterData ) 01231 { 01232 if ( $i > 0 ) 01233 $text .= ",\n" . str_repeat( ' ', $column ); 01234 $parameterType = eZPHPCreator::METHOD_CALL_PARAMETER_VALUE; 01235 $parameterValue = $parameterData[0]; 01236 if ( isset( $parameterData[1] ) ) 01237 $parameterType = $parameterData[1]; 01238 if ( $parameterType == eZPHPCreator::METHOD_CALL_PARAMETER_VALUE ) 01239 $text .= ' ' . $this->thisVariableText( $parameterValue, $column + 1 ); 01240 else if ( $parameterType == eZPHPCreator::METHOD_CALL_PARAMETER_VARIABLE ) 01241 $text .= ' $' . $parameterValue; 01242 ++$i; 01243 } 01244 if ( $i > 0 ) 01245 $text .= ' '; 01246 $text .= ");\n"; 01247 $text = eZPHPCreator::prependSpacing( $text, $spacing ); 01248 $this->write( $text ); 01249 } 01250 01251 /*! 01252 \private 01253 */ 01254 function writeVariableUnset( $element ) 01255 { 01256 $variableName = $element[1]; 01257 $parameters = $element[2]; 01258 $spacing = 0; 01259 if ( isset( $parameters['spacing'] ) and $this->Spacing ) 01260 $spacing = $parameters['spacing']; 01261 $text = "unset( \$$variableName );\n"; 01262 $text = eZPHPCreator::prependSpacing( $text, $spacing ); 01263 $this->write( $text ); 01264 } 01265 01266 /*! 01267 \private 01268 */ 01269 function writeVariableUnsetList( $element ) 01270 { 01271 $variableNames = $element[1]; 01272 01273 if ( count( $variableNames ) ) 01274 { 01275 $parameters = $element[2]; 01276 $spacing = 0; 01277 if ( isset( $parameters['spacing'] ) and $this->Spacing ) 01278 $spacing = $parameters['spacing']; 01279 $text = 'unset( '; 01280 array_walk( $variableNames, create_function( '&$variableName,$key', '$variableName = "\$" . $variableName;') ); 01281 $text .= join( ', ', $variableNames ); 01282 $text .= " );\n"; 01283 $text = eZPHPCreator::prependSpacing( $text, $spacing ); 01284 $this->write( $text ); 01285 } 01286 } 01287 01288 /*! 01289 \private 01290 */ 01291 function writeRawVariable( $variableName, $variableValue ) 01292 { 01293 $this->write( "\${$variableName} = ". var_export( $variableValue, true). ";\n" ); 01294 } 01295 01296 /*! 01297 \private 01298 */ 01299 function writeVariable( $variableName, $variableValue, $assignmentType = eZPHPCreator::VARIABLE_ASSIGNMENT, 01300 $variableParameters = array() ) 01301 { 01302 $variableParameters = array_merge( array( 'full-tree' => false, 01303 'spacing' => 0 ), 01304 $variableParameters ); 01305 $fullTree = $variableParameters['full-tree']; 01306 $spacing = $this->Spacing ? $variableParameters['spacing'] : 0; 01307 $text = $this->variableNameText( $variableName, $assignmentType, $variableParameters ); 01308 $maxIterations = 2; 01309 if ( $fullTree ) 01310 $maxIterations = false; 01311 $text .= $this->thisVariableText( $variableValue, strlen( $text ), 0, $maxIterations ); 01312 $text .= ";\n"; 01313 $text = eZPHPCreator::prependSpacing( $text, $spacing ); 01314 $this->write( $text ); 01315 } 01316 01317 /*! 01318 \private 01319 */ 01320 function temporaryVariableName( $prefix ) 01321 { 01322 $variableName = $prefix . '_' . $this->TemporaryCounter; 01323 ++$this->TemporaryCounter; 01324 return $variableName; 01325 } 01326 01327 /// \privatesection 01328 public $PHPDir; 01329 public $PHPFile; 01330 public $FileResource; 01331 public $Elements; 01332 public $TextChunks; 01333 public $isAtomic; 01334 public $tmpFilename; 01335 public $requestedFilename; 01336 public $Spacing = true; 01337 public $ClusteringEnabled = false; 01338 public $ClusterFileScope = false; 01339 } 01340 ?>