Implement #015359: access.php - new MatchOrder=host_uri
[tinyz:tinyz.git] / kernel / classes / ezscript.php
1 <?php
2 //
3 // Definition of eZScript class
4 //
5 // Created on: <06-Aug-2003 11:06:35 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-2010 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
31 /*! \file
32 */
33
34 /*!
35   \class eZScript ezscript.php
36   \brief Handles the basics of script execution
37
38   By using this class for script execution startup, initializing
39   and shutdown the amount code required to write a new script is
40   reduced significantly.
41
42   It is also recommended to use the eZCLI class in addition to this
43   class.
44
45   What this class will handle is:
46   - Startup of database
47   - Startup/shutdown of session
48   - Debug initialize and display
49   - Text codec initialize
50
51   This class consists of the static functions startup(), initialize()
52   and shutdown().
53
54   A typical usage:
55 \code
56 $script = eZScript::instance();
57
58 $script->startup();
59
60 // Read arguments and modify script accordingly
61
62 $script->initialize();
63
64 // Do the actual script here
65
66 $script->shutdown(); // Finish execution
67
68 \endcode
69
70 */
71
72 require_once( 'access.php' );
73 require_once( 'kernel/common/i18n.php' );
74
75 class eZScript
76 {
77     /*!
78      Constructor
79     */
80     function eZScript( $settings = array() )
81     {
82         $settings = array_merge( array( 'debug-message' => false,
83                                         'debug-output' => false,
84                                         'debug-include' => false,
85                                         'debug-levels' => false,
86                                         'debug-accumulator' => false,
87                                         'debug-timing' => false,
88                                         'use-session' => false,
89                                         'use-extensions' => false,
90                                         'use-modules' => false,
91                                         'user' => false,
92                                         'description' => 'eZ Publish script',
93                                         'site-access' => false,
94                                         'min_version' => false,
95                                         'max_version' => false ),
96                                  $settings );
97         $this->DebugMessage = $settings['debug-message'];
98         $this->UseDebugOutput = $settings['debug-output'];
99         $this->AllowedDebugLevels = $settings['debug-levels'];
100         $this->UseDebugAccumulators = $settings['debug-accumulator'];
101         $this->UseDebugTimingPoints = $settings['debug-timing'];
102         $this->UseIncludeFiles = $settings['debug-include'];
103         $this->UseSession = $settings['use-session'];
104         $this->UseModules = $settings['use-modules'];
105         $this->UseExtensions = $settings['use-extensions'];
106         $this->User = $settings['user'];
107         $this->SiteAccess = $settings['site-access'];
108         $this->Description = $settings['description'];
109         $this->MinVersion = $settings['min_version'];
110         $this->MaxVersion = $settings['max_version'];
111         $this->ExitCode = false;
112         $this->IsQuiet = false;
113         $this->ShowVerbose = false;
114         $this->IsInitialized = false;
115         $this->CurrentOptions = false;
116         $this->CurrentOptionConfig = false;
117         $this->CurrentStandardOptions = false;
118         $this->CurrentExcludeOptions = false;
119         $this->CurrentOptionHelp = false;
120
121         $this->IterationTrueString = '.';
122         $this->IterationFalseString = '~';
123         $this->IterationNumericStrings = false;
124         $this->IterationWrapNumeric = false;
125         $this->IterationIndex = 0;
126         $this->IterationColumn = 0;
127         $this->IterationColumnMax = 70;
128         $this->IterationMax = false;
129         $this->InitializationErrorMessage = 'unknown error';
130     }
131
132     /*!
133      Checks if the script is run on correct eZ Publish version.
134     */
135     function validateVersion()
136     {
137         $versionValidated = false;
138         $ezversion = eZPublishSDK::version();
139         if ( $this->MinVersion !== false )
140         {
141             if ( $this->MaxVersion !== false )
142             {
143                 if ( version_compare( $this->MinVersion, $ezversion , 'le' ) &&
144                      version_compare( $this->MaxVersion, $ezversion , 'ge' ) )
145                 {
146                     return true;
147                 }
148                 return false;
149             }
150             if ( version_compare( $this->MinVersion, $ezversion , 'le' ) )
151             {
152                 return true;
153             }
154             return false;
155         }
156         else
157         {
158             if ( version_compare( $this->MaxVersion, $ezversion , 'ge' ) )
159             {
160                 return true;
161             }
162             return false;
163         }
164     }
165
166     /*!
167      Checks if the script is run in CLI mode, if not it exits with a warning.
168      The PHP local is also initialized if it is used.
169
170      Call this at the very start of your script and always before getOptions() and initialize().
171     */
172     function startup()
173     {
174         error_reporting( E_ALL );
175
176         eZDebug::setHandleType( eZDebug::HANDLE_TO_PHP );
177
178         if ( php_sapi_name() != 'cli' )
179         {
180             $cli = eZCLI::instance();
181             $cli->output( "PHP is currently using the '" . php_sapi_name() . "' interface. Make sure it is using the 'cli' interface." );
182             exit( 1 );
183         }
184
185         $ini = eZINI::instance();
186         $phpLocale = trim( $ini->variable( 'RegionalSettings', 'SystemLocale' ) );
187         if ( $phpLocale != '' )
188         {
189             setlocale( LC_ALL, explode( ',', $phpLocale ) );
190         }
191
192         // Set correct site timezone
193         $timezone = $ini->variable( "TimeZoneSettings", "TimeZone" );
194         if ( $timezone )
195         {
196             date_default_timezone_set( $timezone );
197         }
198     }
199
200     /*!
201      Initializes all settings which are required for the script to run,
202      must be called after startup() and getOptions().
203
204      If you modify the eZScript object using the set* functions you must make sure that
205      is done before this function is called.
206     */
207     function initialize()
208     {
209         if( ob_get_length() != 0 )
210             ob_end_clean();
211         $debugINI = eZINI::instance( 'debug.ini' );
212         eZDebugSetting::setDebugINI( $debugINI );
213
214         // Initialize text codec settings
215         $this->updateTextCodecSettings();
216
217         // Initialize debug settings
218         $this->updateDebugSettings( $this->UseDebugOutput );
219
220         // Set the different permissions/settings.
221         $ini = eZINI::instance();
222         $iniFilePermission = $ini->variable( 'FileSettings', 'StorageFilePermissions' );
223         $iniDirPermission = $ini->variable( 'FileSettings', 'StorageDirPermissions' );
224         $iniVarDirectory = eZSys::cacheDirectory() ;
225
226         eZCodePage::setPermissionSetting( array( 'file_permission' => octdec( $iniFilePermission ),
227                                                  'dir_permission'  => octdec( $iniDirPermission ),
228                                                  'var_directory'   => $iniVarDirectory ) );
229
230         eZExecution::addCleanupHandler( 'eZDBCleanup' );
231         eZExecution::addFatalErrorHandler( 'eZFatalError' );
232
233         eZDebug::setHandleType( eZDebug::HANDLE_FROM_PHP );
234
235         if ( $this->UseExtensions )
236         {
237             // Check for extension
238             require_once( 'kernel/common/ezincludefunctions.php' );
239             eZExtension::activateExtensions( 'default' );
240             // Extension check end
241         }
242
243         require_once( "access.php" );
244         $siteaccess = $this->SiteAccess;
245         if ( $siteaccess )
246         {
247             $access = array( 'name' => $siteaccess,
248                              'type' => eZSiteAccess::TYPE_STATIC );
249         }
250         else
251         {
252             $ini = eZINI::instance();
253             $siteaccess = $ini->variable( 'SiteSettings', 'DefaultAccess' );
254             $access = array( 'name' => $siteaccess,
255                              'type' => eZSiteAccess::TYPE_DEFAULT );
256         }
257
258         $access = eZSiteAccess::change( $access );
259
260         if ( $this->UseExtensions )
261         {
262             // Check for siteaccess extension
263             eZExtension::activateExtensions( 'access' );
264             // Extension check end
265         }
266
267         // Set the global setting which is read by the session lib
268         $GLOBALS['eZSiteBasics']['session-required'] = $this->UseSession;
269
270         if ( $this->UseSession )
271         {
272             $db = eZDB::instance();
273             if ( $db->isConnected() )
274             {
275                 eZSession::start();
276             }
277             else
278             {
279                 $this->IsInitialized = false;
280                 $this->InitializationErrorMessage = 'database error: ' . $db->errorMessage();
281                 return;
282             }
283         }
284
285         if ( $this->User )
286         {
287             $userLogin = $this->User['login'];
288             $userPassword = $this->User['password'];
289             if ( $userLogin and $userPassword )
290             {
291                 $userID = eZUser::loginUser( $userLogin, $userPassword );
292                 if ( !$userID )
293                 {
294                     $cli = eZCLI::instance();
295                     if ( $this->isLoud() )
296                         $cli->warning( 'Failed to login with user ' . $userLogin );
297                     eZExecution::cleanup();
298                     eZExecution::setCleanExit();
299                 }
300             }
301         }
302
303         // Initialize module handling
304         if ( $this->UseModules )
305         {
306             $moduleRepositories = eZModule::activeModuleRepositories( $this->UseExtensions );
307             eZModule::setGlobalPathList( $moduleRepositories );
308         }
309         $this->IsInitialized = true;
310     }
311
312     function isInitialized()
313     {
314         return $this->IsInitialized;
315     }
316
317     function initializationError()
318     {
319         return $this->InitializationErrorMessage;
320     }
321
322     /*!
323      Shuts down the currently running script, the following things will be done:
324      - Remove current session (if sessions are used)
325      - Print debug messages (if debug is enabled)
326      - Call cleanup function using eZExecution
327      - Sets the clean exit flag, that way an exit, die or other stops will not issue an error
328
329      If an exit code is set, PHP will exit with that code set (this means that this function never returns),
330      otherwise this function returns normally.
331     */
332     function shutdown( $exitCode = false, $exitText = false )
333     {
334         $cli = eZCLI::instance();
335         if ( class_exists( 'eZDB' )
336              and eZDB::hasInstance() )
337         {
338             $db = eZDB::instance( false, array( 'show_errors' => false ) );
339             // Perform transaction check
340             $transactionCounterCheck = eZDB::checkTransactionCounter();
341             if ( isset( $transactionCounterCheck['error'] ) )
342                 $cli->error( $transactionCounterCheck['error'] );
343
344             if ( $this->UseSession and
345                  $db->isConnected() )
346             {
347                 eZUser::logoutCurrent();
348                 eZSession::remove();
349             }
350         }
351
352         $webOutput = $cli->isWebOutput();
353
354         if ( $this->UseDebugOutput or
355              eZDebug::isDebugEnabled() )
356         {
357             if ( $this->DebugMessage )
358                 fputs( STDERR, $this->DebugMessage );
359             fputs( STDERR, eZDebug::printReport( false, $webOutput, true,
360                                                  $this->AllowedDebugLevels, $this->UseDebugAccumulators,
361                                                  $this->UseDebugTimingPoints, $this->UseIncludeFiles ) );
362         }
363
364         eZExecution::cleanup();
365         eZExecution::setCleanExit();
366         $this->IsInitialized = false;
367         if ( $exitCode !== false )
368             $this->ExitCode = $exitCode;
369         if ( $this->ExitCode !== false )
370         {
371             if ( $exitText !== false )
372                 $cli->output( $exitText );
373             exit( $this->ExitCode );
374         }
375     }
376
377     /*!
378      Sets the text message which is shown before the debug list.
379      There will be a default message which should suit most scripts.
380      \note This requires that setUseDebugOutput is set to true or that
381            the user has enabled debug in the arguments.
382     */
383     function setDebugMessage( $message )
384     {
385         $this->DebugMessage = $message;
386     }
387
388     /*!
389      Sets whether debug output should be enabled or not.
390      \note This can also be called by the argument parser if the user specifies to show debug.
391     */
392     function setUseDebugOutput( $useDebug )
393     {
394         $this->UseDebugOutput = $useDebug;
395     }
396
397     /*!
398      Sets whether accumulators should be shown on debug output or not.
399      \note This requires that setUseDebugOutput is set to true or that
400            the user has enabled debug in the arguments.
401     */
402     function setUseDebugAccumulators( $useAccumulators )
403     {
404         $this->UseDebugAccumulators = $useAccumulators;
405     }
406
407     /*!
408      Sets whether timing points should be shown on debug output or not.
409      \note This requires that setUseDebugOutput is set to true or that
410            the user has enabled debug in the arguments.
411     */
412     function setUseDebugTimingPoints( $useTimingPoints )
413     {
414         $this->UseDebugTimingPoints = $useTimingPoints;
415     }
416
417     /*!
418      Sets whether include files should be shown on debug output or not.
419      \note This requires that setUseDebugOutput is set to true or that
420            the user has enabled debug in the arguments.
421     */
422     function setUseIncludeFiles( $useIncludeFiles )
423     {
424         $this->UseIncludeFiles = $useIncludeFiles;
425     }
426
427     /*!
428      Sets which debug levels are to be shown on debug output, this must be an array
429      with EZ_LEVEL_* definitions taken from eZDebug.
430      \note This requires that setUseDebugOutput is set to true or that
431            the user has enabled debug in the arguments.
432     */
433     function setAllowedDebugLevels( $allowedDebugLevels )
434     {
435         $this->AllowedDebugLevels = $allowedDebugLevels;
436     }
437
438     /*!
439      Sets whether session is to be used or not.
440      \note This will only work if it is set before initialized() is called.
441      \note If session is enabled the current session data will be removed on shutdown().
442     */
443     function setUseSession( $useSession )
444     {
445         $this->UseSession = $useSession;
446     }
447
448     /*!
449      Sets whether extension support is to be added or not.
450      \note This will only work if it is set before initialized() is called.
451     */
452     function setUseExtensions( $useExtensions )
453     {
454         $this->UseExtensions = $useExtensions;
455     }
456
457     /*!
458      Sets the current site access to \a $siteAccess.
459      \note This will only work if it is set before initialized() is called.
460      \note This will be filled in if getOptions() is used and the user specifices it in the arguments.
461     */
462     function setUseSiteAccess( $siteAccess )
463     {
464         $this->SiteAccess = $siteAccess;
465     }
466
467     /*!
468      \return the currently set siteaccess or \c false if none is set.
469     */
470     function usedSiteAccess()
471     {
472         return $this->SiteAccess;
473     }
474
475     function setUseModules( $useModules )
476     {
477         $this->UseModules = $useModules;
478     }
479
480     function setUser( $userLogin, $userPassword )
481     {
482         $this->User = array( 'login' => $userLogin,
483                              'password' => $userPassword );
484     }
485
486     /*!
487      Controls whether verbose output is used or not, use \c false to turn it off,
488      \c true to turn it on or a number to select the verbose level (\c true == 1).
489      The actual behaviour of verbose output depends on the script, however enabling
490      it will make sure iteration looping displays the iteration name instead of a dot.
491     */
492     function setShowVerboseOutput( $verbose )
493     {
494         if ( $verbose === true )
495             $verbose = 1;
496         $this->ShowVerbose = $verbose;
497     }
498
499     /*!
500      \return the verbosity level for the script, will be \c false or a number in the range 1 and up.
501     */
502     function verboseOutputLevel()
503     {
504         return $this->ShowVerbose;
505     }
506
507     /*!
508      \return the currently set options if getOptions() has been run or \c false if no options are set.
509     */
510     function currentOptions()
511     {
512         return $this->CurrentOptions;
513     }
514
515     /*!
516      \return the current option configuration, this will be a mix of the standard options and script specified.
517     */
518     function currentOptionConfig()
519     {
520         return $this->CurrentOptionConfig;
521     }
522
523     /*!
524      Sets the current exit code which will be set with an exit() call in shutdown().
525      If you don't want shutdown() to exit automatically set it to \c false.
526     */
527     function setExitCode( $code = false )
528     {
529         $this->ExitCode = $code;
530     }
531
532     function exitCode()
533     {
534         return $this->ExitCode;
535     }
536
537     /*!
538      Sets whether any output should be used or not.
539      \sa isQuiet, isLoud
540      \note it will also call eZCLI::setIsQuiet()
541     */
542     function setIsQuiet( $isQuiet )
543     {
544         $cli = eZCLI::instance();
545         $this->IsQuiet = $isQuiet;
546         $cli->setIsQuiet( $isQuiet );
547     }
548
549     /*!
550      \return \c true if output is not allowed.
551      \sa isLoud
552     */
553     function isQuiet()
554     {
555         return $this->IsQuiet;
556     }
557
558     /*!
559      \return \c true if output is allowed.
560      \sa isQuiet
561     */
562     function isLoud()
563     {
564         return !$this->IsQuiet;
565     }
566
567     function setIterationData( $trueString, $falseString,
568                                $numericStrings = false, $wrapNumeric = false )
569     {
570         $this->IterationTrueString = $trueString;
571         $this->IterationFalseString = $falseString;
572         $this->IterationNumericStrings = $numericStrings;
573         $this->IterationWrapNumeric = $wrapNumeric;
574     }
575
576     function resetIteration( $iterationMax = false, $startIndex = 0 )
577     {
578         $this->IterationIndex = $startIndex;
579         $this->IterationColumn = 0;
580         $this->IterationMax = $iterationMax;
581     }
582
583     function iterate( $cli, $status, $text = false )
584     {
585         if ( !$this->IterationNumericStrings )
586             $status = (bool)$status;
587         if ( $this->verboseOutputLevel() === false or
588              $text === false )
589         {
590             if ( is_bool( $status ) )
591             {
592                 $statusText = $status ? $this->IterationTrueString : $this->IterationFalseString;
593             }
594             else
595             {
596                 if ( $this->IterationWrapNumeric )
597                     $status = $status % count( $this->IterationNumericStrings );
598                 if ( $status < count( $this->IterationNumericStrings ) )
599                     $statusText = $this->IterationNumericStrings[$status];
600                 else
601                     $statusText = ' ';
602             }
603             $endLine = false;
604             $changeLine = false;
605             ++$this->IterationIndex;
606             ++$this->IterationColumn;
607             $iterationColumn = $this->IterationColumn;
608             if ( $this->IterationColumn >= $this->IterationColumnMax )
609             {
610                 $this->IterationColumn = 0;
611                 $changeLine = true;
612             }
613             if ( $this->IterationMax !== false )
614             {
615                 if ( $this->IterationIndex >= $this->IterationMax )
616                 {
617                     $this->IterationColumn = 0;
618                     $changeLine = true;
619                 }
620             }
621             if ( $changeLine )
622             {
623                 if ( $this->IterationMax !== false )
624                 {
625                     $spacing = $this->IterationColumnMax - $iterationColumn;
626                     $percent = ( $this->IterationIndex * 100 ) / $this->IterationMax;
627                     if ( $percent > 100.0 )
628                         $percent = 100;
629                     else
630                         $spacing += 1;
631                     $percentText = number_format( $percent, 2 ) . '%';
632                     $statusText .= str_repeat( ' ', $spacing );
633                     $statusText .= $percentText;
634                 }
635                 $endLine = true;
636             }
637             $cli->output( $statusText, $endLine );
638         }
639         else
640         {
641             $statusLevel = $status;
642             if ( is_bool( $status ) )
643                 $statusLevel = $status ? 0 : 1;
644             if ( $statusLevel > 0 )
645             {
646                 --$statusLevel;
647                 $statusLevels = array( 'warning', 'failure' );
648                 if ( $statusLevel > count( $statusLevels ) )
649                     $statusLevel = count( $statusLevels ) - 1;
650                 $levelText = $statusLevels[$statusLevel];
651                 $cli->output( $cli->stylize( $levelText, $text ) );
652             }
653             else
654             {
655                 $cli->output( $text );
656             }
657         }
658     }
659
660     function showHelp( $useStandardOptions = false, $optionConfig = false, $optionHelp = false, $argumentConfig = false, $arguments = false )
661     {
662         if ( $useStandardOptions === false )
663         {
664             $useStandardOptions = $this->CurrentStandardOptions;
665         }
666         if ( $optionConfig === false )
667         {
668             $optionConfig = $this->CurrentOptionConfig;
669         }
670         if ( $optionHelp === false )
671         {
672             $optionHelp = $this->CurrentOptionHelp;
673         }
674         if ( $argumentConfig === false )
675         {
676             $argumentConfig = $this->ArgumentConfig;
677         }
678         $optionList = array();
679         foreach ( $optionConfig['list'] as $configItem )
680         {
681             if ( in_array( $configItem['name'], $this->CurrentExcludeOptions ) )
682                 continue;
683             $optionText = '-';
684             if ( $configItem['is-long-option'] )
685                 $optionText .= '-';
686             $optionText .= $configItem['name'];
687             if ( $configItem['has-value'] and $configItem['is-long-option'] )
688                 $optionText .= "=VALUE";
689             $hasMultipleValues = ( $configItem['quantifier']['min'] > 1 or
690                                    $configItem['quantifier']['max'] === false or
691                                    $configItem['quantifier']['max'] > 1 );
692             if ( $hasMultipleValues )
693                 $optionText .= "...";
694             $optionDescription = '';
695             if ( isset( $optionHelp[$configItem['name']] ) )
696                 $optionDescription = $optionHelp[$configItem['name']];
697             $optionList[] = array( $optionText, $optionDescription );
698         }
699         if ( $arguments === false )
700         {
701             $arguments = $_SERVER['argv'];
702             $program = $arguments[0];
703         }
704         $cli = eZCLI::instance();
705         $generalOptionList = array();
706         $generalOptionList = array();
707         if ( $useStandardOptions )
708         {
709             $generalOptionList[] = array( '-h,--help', 'display this help and exit');
710             $generalOptionList[] = array( '-q,--quiet', 'do not give any output except when errors occur' );
711             if ( $useStandardOptions['siteaccess'] )
712                 $generalOptionList[] = array( '-s,--siteaccess', "selected siteaccess for operations,\nif not specified default siteaccess is used" );
713             if ( $useStandardOptions['debug'] )
714                 $generalOptionList[] = array( '-d,--debug...', ( "display debug output at end of execution,\n" .
715                                                                  "the following debug items can be controlled: \n" .
716                                                                  "all, accumulator, include, timing, error, warning, debug, notice or strict." ) );
717             if ( $useStandardOptions['colors'] )
718             {
719                 $generalOptionList[] = array( '-c,--colors', 'display output using ANSI colors (default)' );
720                 $generalOptionList[] = array( '--no-colors', 'do not use ANSI coloring' );
721             }
722             if ( $useStandardOptions['user'] )
723             {
724                 $generalOptionList[] = array( '-l,--login USER', 'login with USER and use it for all operations' );
725                 $generalOptionList[] = array( '-p,--password PWD', 'use PWD as password for USER' );
726             }
727             if ( $useStandardOptions['log'] )
728             {
729                 $generalOptionList[] = array( '--logfiles', 'create log files' );
730                 $generalOptionList[] = array( '--no-logfiles', 'do not create log files (default)' );
731             }
732             if ( $useStandardOptions['verbose'] )
733             {
734                 $generalOptionList[] = array( '-v,--verbose...', "display more information, \nused multiple times will increase amount of information" );
735             }
736             if( $useStandardOptions['root'] )
737             {
738                 $generalOptionList[] = array( '-r,--allow-root-user', "Allows the script to be run by the root user" );
739             }
740         }
741         $description = $this->Description;
742         $helpText =  "Usage: " . $program;
743         if ( count( $optionList ) > 0 or count( $generalOptionList ) > 0 )
744         {
745             $helpText .= " [OPTION]...";
746         }
747         if ( $argumentConfig && isset( $argumentConfig['list'] ) && is_array( $argumentConfig['list'] ) )
748         {
749             foreach ( $argumentConfig['list'] as $argumentItem )
750             {
751                 $argumentName = strtoupper( $argumentItem['name'] );
752                 $quantifier = $argumentItem['quantifier'];
753                 if ( $quantifier['min'] > 1 or $quantifier['max'] === false or $quantifier['max'] > 1 )
754                     $helpText .= " [$argumentName]...";
755                 else
756                     $helpText .= " [$argumentName]";
757             }
758         }
759         if ( $description )
760             $helpText .= "\n" . $description . "\n";
761         if ( count( $generalOptionList ) > 0 )
762         {
763             $helpText .= "\nGeneral options:\n";
764             $maxLength = 0;
765             foreach ( $generalOptionList as $optionItem )
766             {
767                 $maxLength = max( strlen( $optionItem[0] ), $maxLength );
768             }
769             $spacingLength = $maxLength + 2;
770             foreach ( $generalOptionList as $optionItem )
771             {
772                 $option = $optionItem[0];
773                 $optionDescription = $optionItem[1];
774                 $optionLines = explode( "\n", $option );
775                 $optionDescriptionLines = explode( "\n", $optionDescription );
776                 $count = max( count( $optionLines ), count( $optionDescriptionLines ) );
777                 for ( $i = 0; $i < $count; ++$i )
778                 {
779                     $optionText = '';
780                     if ( isset( $optionLines[$i] ) )
781                         $optionText = $optionLines[$i];
782                     $optionDescriptionText = '';
783                     if ( isset( $optionDescriptionLines[$i] ) )
784                         $optionDescriptionText = $optionDescriptionLines[$i];
785                     $spacing = $spacingLength - strlen( $optionText );
786                     if ( $optionText or $optionDescriptionText )
787                         $helpText .= '  ';
788                     $helpText .= $optionText;
789                     if ( $i > 0 )
790                         $spacing += 2;
791                     if ( $optionDescriptionText )
792                         $helpText .= str_repeat( ' ', $spacing ) . $optionDescriptionText;
793                     $helpText .= "\n";
794                 }
795             }
796         }
797         if ( count( $optionList ) > 0 )
798         {
799             $helpText .= "\nOptions:\n";
800             $maxLength = 0;
801             foreach ( $optionList as $optionItem )
802             {
803                 $maxLength = max( strlen( $optionItem[0] ), $maxLength );
804             }
805             $spacingLength = $maxLength + 2;
806             foreach ( $optionList as $optionItem )
807             {
808                 $option = $optionItem[0];
809                 $optionDescription = $optionItem[1];
810                 $optionLines = explode( "\n", $option );
811                 $optionDescriptionLines = explode( "\n", $optionDescription );
812                 $count = max( count( $optionLines ), count( $optionDescriptionLines ) );
813                 for ( $i = 0; $i < $count; ++$i )
814                 {
815                     $optionText = '';
816                     if ( isset( $optionLines[$i] ) )
817                         $optionText = $optionLines[$i];
818                     $optionDescriptionText = '';
819                     if ( isset( $optionDescriptionLines[$i] ) )
820                         $optionDescriptionText = $optionDescriptionLines[$i];
821                     $spacing = $spacingLength - strlen( $optionText );
822                     if ( $optionText or $optionDescriptionText )
823                         $helpText .= '  ';
824                     $helpText .= $optionText;
825                     if ( $i > 0 )
826                         $spacing += 2;
827                     if ( $optionDescriptionText )
828                         $helpText .= str_repeat( ' ', $spacing ) . $optionDescriptionText;
829                     $helpText .= "\n";
830                 }
831             }
832         }
833         $cli->output( $helpText );
834     }
835
836     /*!
837      Parse command line into options array. If stanadrd options are in use, carry
838      out the associated task (eg. switch siteaccess ir logged-in user)
839      /param $config see ezcli::parseOptionString
840      /param $argumentConfig  see ezcli::getOptions (unused for now)
841      /param $optionHelp string echoed to screen when script invoked with -h/--help
842      /param $arguments array of arguments. If false, command line is parsed automatically
843      /param $useStandardOptions true or an array of standard options to be used.
844        standard options are: 'debug', 'colors', 'log', 'siteaccess', 'verbose', 'user' (false), and can be set to false to be disabled
845     */
846     function getOptions( $config = '', $argumentConfig = '', $optionHelp = false,
847                          $arguments = false, $useStandardOptions = true )
848     {
849         if ( is_string( $config ) )
850             $config = eZCLI::parseOptionString( $config, $tmpConfig );
851         if ( is_string( $argumentConfig ) )
852             $argumentConfig = eZCLI::parseOptionString( $argumentConfig, $tmpArgumentConfig );
853
854         if ( $useStandardOptions )
855         {
856             if ( !is_array( $useStandardOptions ) )
857                 $useStandardOptions = array();
858             $useStandardOptions = array_merge( array( 'debug' => true,
859                                                       'colors' => true,
860                                                       'log' => true,
861                                                       'siteaccess' => true,
862                                                       'verbose' => true,
863                                                       'root' => true,
864                                                       'user' => false ),
865                                                $useStandardOptions );
866         }
867
868         if ( $useStandardOptions )
869         {
870             $optionConfig = $config;
871             $excludeOptions = array();
872             $optionString = "[h|help][q|quiet]";
873             $excludeOptions[] = 'h';
874             $excludeOptions[] = 'help';
875             $excludeOptions[] = 'q';
876             $excludeOptions[] = 'quiet';
877             if ( $useStandardOptions['debug'] )
878             {
879                 $optionString .= "[d;*|debug;*]";
880                 $excludeOptions[] = 'd';
881                 $excludeOptions[] = 'debug';
882             }
883             if ( $useStandardOptions['colors'] )
884             {
885                 $optionString .= "[c|colors][no-colors]";
886                 $excludeOptions[] = 'c';
887                 $excludeOptions[] = 'colors';
888                 $excludeOptions[] = 'no-colors';
889             }
890             if ( $useStandardOptions['log'] )
891             {
892                 $optionString .= "[logfiles][no-logfiles]";
893                 $excludeOptions[] = 'logfiles';
894                 $excludeOptions[] = 'no-logfiles';
895             }
896             if ( $useStandardOptions['siteaccess'] )
897             {
898                 $optionString .= "[s:|siteaccess:]";
899                 $excludeOptions[] = 's';
900                 $excludeOptions[] = 'siteaccess';
901             }
902             if ( $useStandardOptions['user'] )
903             {
904                 $optionString .= "[l:|login:][p:|password:]";
905                 $excludeOptions[] = 'l';
906                 $excludeOptions[] = 'login';
907                 $excludeOptions[] = 'p';
908                 $excludeOptions[] = 'password';
909             }
910             if ( $useStandardOptions['verbose'] )
911             {
912                 $optionString .= "[v*|verbose*]";
913                 $excludeOptions[] = 'v';
914                 $excludeOptions[] = 'verbose';
915             }
916             if( $useStandardOptions['root'] )
917             {
918                 $optionString .= "[r?|allow-root-user?]";
919                 $excludeOptions[] = 'r';
920                 $excludeOptions[] = 'allow-root-user';
921             }
922
923             $config = eZCLI::parseOptionString( $optionString, $optionConfig );
924         }
925         $cli = eZCLI::instance();
926         $options = $cli->getOptions( $config, $argumentConfig, $arguments );
927         $this->CurrentOptionConfig = $config;
928         $this->CurrentOptions = $options;
929         $this->CurrentStandardOptions = $useStandardOptions;
930         $this->CurrentExcludeOptions = $excludeOptions;
931         $this->CurrentOptionHelp = $optionHelp;
932         $this->ArgumentConfig = $argumentConfig;
933         if ( !$options )
934         {
935             if ( !$this->IsInitialized )
936                 $this->initialize();
937             $this->shutdown( 1 );
938         }
939
940         if ( $useStandardOptions )
941         {
942             if ( function_exists( 'posix_getuid' ) )
943             {
944                 if( posix_getuid() === 0 )
945                 {
946                     if( !$options['allow-root-user'] )
947                     {
948                         $cli->warning( "Running scripts as root may be dangerous." );
949                         $cli->warning( "If you think you know what you are doing, you can run this script with the " );
950                         $cli->warning( "root account by appending the parameter --allow-root-user." );
951
952                         exit( 1 );
953                     }
954                     else
955                     {
956                         // ho no, you are not going to be quiet while
957                         // running with root priviledges
958                         $this->setIsQuiet( false );
959
960                         $cli = eZCLI::instance();
961
962                         $cli->warning( 'With great power comes great responsibility.' );
963                         $cli->warning( "You have 10 seconds to break the script (press Ctrl-C)." );
964                         sleep( 10 );
965                     }
966                 }
967             }
968
969             if ( $options['quiet'] )
970                 $this->setIsQuiet( true );
971             $useColors = true;
972             if ( $options['colors'] )
973                 $useColors = true;
974             if ( $options['no-colors'] )
975                 $useColors = false;
976             $cli->setUseStyles( $useColors );
977             if ( $options['debug'] )
978             {
979                 $levels = array();
980                 foreach ( $options['debug'] as $debugOption )
981                 {
982                     $levels = array_merge( $levels, explode( ',', $debugOption ) );
983                 }
984                 $allowedDebugLevels = array();
985                 $useDebugAccumulators = false;
986                 $useDebugTimingpoints = false;
987                 $useIncludeFiles = false;
988                 foreach ( $levels as $level )
989                 {
990                     if ( $level == 'all' )
991                     {
992                         $useDebugAccumulators = true;
993                         $allowedDebugLevels = false;
994                         $useDebugTimingpoints = true;
995                         break;
996                     }
997                     if ( $level == 'accumulator' )
998                     {
999                         $useDebugAccumulators = true;
1000                         continue;
1001                     }
1002                     if ( $level == 'timing' )
1003                     {
1004                         $useDebugTimingpoints = true;
1005                         continue;
1006                     }
1007                     if ( $level == 'include' )
1008                     {
1009                         $useIncludeFiles = true;
1010                     }
1011                     if ( $level == 'strict' )
1012                         $level = eZDebug::LEVEL_STRICT;
1013                     else if ( $level == 'error' )
1014                         $level = eZDebug::LEVEL_ERROR;
1015                     else if ( $level == 'warning' )
1016                         $level = eZDebug::LEVEL_WARNING;
1017                     else if ( $level == 'debug' )
1018                         $level = eZDebug::LEVEL_DEBUG;
1019                     else if ( $level == 'notice' )
1020                         $level = eZDebug::LEVEL_NOTICE;
1021                     else if ( $level == 'timing' )
1022                         $level = eZDebug::EZ_LEVEL_TIMING;
1023                     $allowedDebugLevels[] = $level;
1024                 }
1025                 $this->setUseDebugOutput( true );
1026                 $this->setAllowedDebugLevels( $allowedDebugLevels );
1027                 $this->setUseDebugAccumulators( $useDebugAccumulators );
1028                 $this->setUseDebugTimingPoints( $useDebugTimingpoints );
1029                 $this->setUseIncludeFiles( $useIncludeFiles );
1030                 $this->setDebugMessage( "\n\n" . str_repeat( '#', 36 ) . $cli->style( 'emphasize' ) . " DEBUG " . $cli->style( 'emphasize-end' )  . str_repeat( '#', 36 ) . "\n" );
1031             }
1032             if ( count( $options['verbose'] ) > 0 )
1033             {
1034                 $this->setShowVerboseOutput( count( $options['verbose'] ) );
1035             }
1036             if ( $options['help'] )
1037             {
1038                 if ( !$this->IsInitialized )
1039                     $this->initialize();
1040                 $this->showHelp();
1041                 $this->shutdown( 0 );
1042             }
1043             if ( isset( $options['siteaccess'] ) and $options['siteaccess'] )
1044                 $this->setUseSiteAccess( $options['siteaccess'] );
1045
1046             if ( isset( $options['login'] ) and $options['login'] )
1047                 $this->setUser( $options['login'], isset( $options['password'] ) ? $options['password'] : false );
1048         }
1049         return $options;
1050     }
1051
1052     /**
1053      * Returns a shared instance of the eZScript class.
1054      *
1055      * @param $settings array Used by the first generated instance, but ignored for subsequent calls.
1056      * @return eZScript
1057      */
1058     static function instance( $settings = array() )
1059     {
1060         if ( !isset( $GLOBALS['eZScriptInstance'] ) or
1061              !( $GLOBALS['eZScriptInstance'] instanceof eZScript ) )
1062         {
1063             $GLOBALS['eZScriptInstance'] = new eZScript( $settings );
1064         }
1065         return $GLOBALS['eZScriptInstance'];
1066     }
1067
1068     /*!
1069      \static
1070      Reads settings from site.ini and passes them to eZDebug.
1071     */
1072     function updateDebugSettings( $useDebug = null )
1073     {
1074         global $debugOutput;
1075         global $useLogFiles;
1076         $ini = eZINI::instance();
1077         $cli = eZCLI::instance();
1078         $debugSettings = array();
1079         $debugSettings['debug-enabled'] = ( $ini->variable( 'DebugSettings', 'DebugOutput' ) == 'enabled' and
1080                                             $ini->variable( 'DebugSettings', 'ScriptDebugOutput' ) == 'enabled' );
1081         if ( $useDebug !== null )
1082             $debugSettings['debug-enabled'] = $useDebug;
1083         $debugSettings['debug-by-ip'] = $ini->variable( 'DebugSettings', 'DebugByIP' ) == 'enabled';
1084         $debugSettings['debug-ip-list'] = $ini->variable( 'DebugSettings', 'DebugIPList' );
1085         if ( isset( $debugOutput ) )
1086             $debugSettings['debug-enabled'] = $debugOutput;
1087         $debugSettings['debug-log-files-enabled'] = $useLogFiles;
1088         if ( $cli->useStyles() and
1089              !$cli->isWebOutput() )
1090         {
1091             $debugSettings['debug-styles'] = $cli->terminalStyles();
1092         }
1093         $logList = $ini->variable( 'DebugSettings', 'AlwaysLog' );
1094         $logMap = array( 'notice' => eZDebug::LEVEL_NOTICE,
1095                          'warning' => eZDebug::LEVEL_WARNING,
1096                          'error' => eZDebug::LEVEL_ERROR,
1097                          'debug' => eZDebug::LEVEL_DEBUG,
1098                          'strict' => eZDebug::LEVEL_STRICT );
1099         $debugSettings['always-log'] = array();
1100         foreach ( $logMap as $name => $level )
1101         {
1102             $debugSettings['always-log'][$level] = in_array( $name, $logList );
1103         }
1104         eZDebug::updateSettings( $debugSettings );
1105     }
1106
1107     /*!
1108      \static
1109      Reads settings from i18n.ini and passes them to eZTextCodec.
1110     */
1111     function updateTextCodecSettings()
1112     {
1113         $ini = eZINI::instance( 'i18n.ini' );
1114         $i18nSettings = array();
1115         $i18nSettings['internal-charset'] = $ini->variable( 'CharacterSettings', 'Charset' );
1116         $i18nSettings['http-charset'] = $ini->variable( 'CharacterSettings', 'HTTPCharset' );
1117         $i18nSettings['mbstring-extension'] = $ini->variable( 'CharacterSettings', 'MBStringExtension' ) == 'enabled';
1118         eZTextCodec::updateSettings( $i18nSettings );
1119     }
1120
1121     /// \privatesection
1122     public $InitializationErrorMessage;
1123     public $DebugMessage;
1124     public $UseDebugOutput;
1125     public $UseSession;
1126     public $UseExtensions;
1127     public $UseModules;
1128     public $User;
1129     public $SiteAccess;
1130     public $ExitCode;
1131     public $IsQuiet;
1132     public $ShowVerbose;
1133 }
1134
1135 function eZDBCleanup()
1136 {
1137     if ( class_exists( 'ezdb' )
1138          and eZDB::hasInstance() )
1139     {
1140         $db = eZDB::instance();
1141         $db->setIsSQLOutputEnabled( false );
1142     }
1143 //     session_write_close();
1144 }
1145
1146 function eZFatalError()
1147 {
1148     $cli = eZCLI::instance();
1149     $endl = $cli->endlineString();
1150     $webOutput = $cli->isWebOutput();
1151     $bold = $cli->style( 'bold' );
1152     $unbold = $cli->style( 'bold-end' );
1153     $par = $cli->style( 'paragraph' );
1154     $unpar = $cli->style( 'paragraph-end' );
1155
1156     $allowedDebugLevels = true;
1157     $useDebugAccumulators = true;
1158     $useDebugTimingpoints = true;
1159
1160     eZDebug::setHandleType( eZDebug::HANDLE_NONE );
1161     if ( !$webOutput )
1162         fputs( STDERR, $endl );
1163     fputs( STDERR, $bold . "Fatal error" . $unbold . ": eZ Publish did not finish its request$endl" );
1164     fputs( STDERR, $par . "The execution of eZ Publish was abruptly ended, the debug output is present below." . $unpar . $endl );
1165     fputs( STDERR, eZDebug::printReport( false, $webOutput, true ) );
1166 }
1167
1168 /*!
1169   Dummy function, required by some scripts in eZ Publish.
1170 */
1171 function eZUpdateDebugSettings( $useDebug = null )
1172 {
1173 }
1174
1175 /*!
1176   Dummy function, required by some scripts in eZ Publish.
1177 */
1178 function eZUpdateTextCodecSettings()
1179 {
1180 }
1181
1182 ?>