Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • None
  • system
    • base
    • caching
    • console
    • db
      • ar
      • schema
    • validators
    • web
      • actions
      • auth
      • helpers
      • widgets
        • captcha
        • pagers
  • zii
    • widgets
      • grid

Classes

  • ActionFormModel
  • ArrayUtil
  • ArrayValidator
  • AssociatedMediaBehavior
  • AuxLib
  • Changelog
  • DetailView
  • EncryptUtilTmp
  • EventsWidgetFieldFormatter
  • FailedLogins
  • FieldFormatter
  • FieldFormatterBase
  • FieldInputRenderer
  • FileFieldBehavior
  • FiltersForm
  • FilterUtil
  • FineDiff
  • FineDiffCopyOp
  • FineDiffDeleteOp
  • FineDiffInsertOp
  • FineDiffOp
  • FineDiffOps
  • FineDiffReplaceOp
  • GlobalCSSFormModel
  • GlobalImportFormModel
  • GoogleAuthenticator
  • JSONFieldsBehavior
  • JSONResponse
  • MediaFieldFormatter
  • MediaSelector
  • MobileActiveRecordFieldFormatter
  • MobileActivityFeed
  • MobileChartDashboard
  • MobileFieldFormatter
  • MobileFieldInputRenderer
  • ModuleModelNameValidator
  • MultiChildNode
  • MultiTypeAutocomplete
  • PasswordUtil
  • ProductFeature
  • ProfileWidgetLayout
  • QueryParamGenerator
  • RecordLimitBehavior
  • RecordView
  • RecordViewWidgetLayout
  • RelationshipsGridModel
  • RelationshipsJoin
  • RepairUserDataCommand
  • RequestUtil
  • RequiredIfNotSetValidator
  • ResponseUtil
  • RunMigrationScriptCommand
  • ServiceWebFormDesigner
  • Settings
  • StringUtil
  • TestEmailAction
  • TestEmailActionForm
  • ThemeGenerator
  • TimerUtil
  • TopicsFieldFormatter
  • TopicsWidgetLayout
  • TransactionalViewFieldFormatter
  • UrlUtil
  • ValidLinkValidator
  • WebFormDesigner
  • WebLeadFormDesigner
  • X2ActiveRecordBehavior
  • X2ActiveRecordFieldFormatter
  • X2ButtonColumn
  • X2ConditionList
  • X2ConsoleCommand
  • X2ControllerBehavior
  • X2DataColumn
  • X2DuplicateBehavior
  • X2Flashes
  • X2GridViewFieldFormatter
  • X2IPAddress
  • X2LeadsDataColumn
  • X2MergeableBehavior
  • X2MessageSource
  • X2MobileControllerBehavior
  • X2MobileProfileControllerBehavior
  • X2MobileQuotesControllerBehavior
  • X2MobileSiteControllerBehavior
  • X2MobileTopicsControllerBehavior
  • X2ModelConversionBehavior
  • X2ModelConversionWidget
  • X2ModelForeignKeyValidator
  • X2ModelUniqueIndexValidator
  • X2NonWebUser
  • X2StaticDropdown
  • X2StaticField
  • X2StaticFieldsBehavior
  • X2UrlManager
  • X2Validator
  • X2WidgetBehavior

Interfaces

  • AdminOwnedCredentials

Exceptions

  • CampaignMailingException
  • CodeExchangeException
  • GetCredentialsException
  • NoRefreshTokenException
  • NoUserIdException
  • StringUtilException

Functions

  • checkCurrency
  • checkDNS
  • checkServerVar
  • checkTimezone
  • decodeQuotes
  • echoIcons
  • encodeQuotes
  • exceptionForError
  • getField
  • getLanguageName
  • getModuleTitle
  • handleReqError
  • handleReqException
  • installer_t
  • installer_tr
  • isAllowedDir
  • mediaMigrationRrmdir
  • migrateMediaDir
  • printGraph
  • printR
  • renderFields
  • reqShutdown
  • RIP
  • translateOptions
  • tryGetRemote
  • Overview
  • Package
  • Function
  • Tree
  1: <?php
  2: /*****************************************************************************************
  3:  * X2Engine Open Source Edition is a customer relationship management program developed by
  4:  * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
  5:  * 
  6:  * This program is free software; you can redistribute it and/or modify it under
  7:  * the terms of the GNU Affero General Public License version 3 as published by the
  8:  * Free Software Foundation with the addition of the following permission added
  9:  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 10:  * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
 11:  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 12:  * 
 13:  * This program is distributed in the hope that it will be useful, but WITHOUT
 14:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 15:  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 16:  * details.
 17:  * 
 18:  * You should have received a copy of the GNU Affero General Public License along with
 19:  * this program; if not, see http://www.gnu.org/licenses or write to the Free
 20:  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 21:  * 02110-1301 USA.
 22:  * 
 23:  * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
 24:  * California 95067, USA. or at email address contact@x2engine.com.
 25:  * 
 26:  * The interactive user interfaces in modified source and object code versions
 27:  * of this program must display Appropriate Legal Notices, as required under
 28:  * Section 5 of the GNU Affero General Public License version 3.
 29:  * 
 30:  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 31:  * these Appropriate Legal Notices must retain the display of the "Powered by
 32:  * X2Engine" logo. If the display of the logo is not reasonably feasible for
 33:  * technical reasons, the Appropriate Legal Notices must display the words
 34:  * "Powered by X2Engine".
 35:  *****************************************************************************************/
 36: 
 37: /**
 38:  * @file protected/components/views/requirements.php
 39:  * @author Demitri Morgan <demitri@x2engine.com>
 40:  *
 41:  * Multi-role requirements-check script. Can be included as part of another page,
 42:  * run as its own standalone script, or used to return requirements check data
 43:  * as an array.
 44:  */
 45: 
 46: /////////////////
 47: // SET GLOBALS //
 48: /////////////////
 49: $document = '<html><header><title>X2Engine System Requirements Check</title>{headerContent}</head><body><div style="width: 680px; border:1px solid #DDD; margin: 25px auto 25px auto; padding: 20px;font-family:sans-serif;">{bodyContent}</div></body></html>';
 50: $totalFailure = array(
 51:     "<h1>This server definitely, most certainly cannot run X2Engine.</h1><p>Not even the system requirements checker script itself could run properly on this server. It encountered the following {scenario}:</p>\n<pre style=\"overflow-x:auto;margin:5px;padding:5px;border:1px red dashed;\">\n",
 52:     "\n</pre>"
 53: );
 54: $mode = php_sapi_name() == 'cli' ? 'cli' : 'web';
 55: $responding = false;
 56: if(!isset($thisFile))
 57:     $thisFile = __FILE__;
 58: if(!isset($standalone))
 59:     $standalone = realpath($thisFile) === realpath(__FILE__);
 60: $returnArray = (isset($returnArray)?$returnArray:false) || $mode == 'cli';
 61: if(!$standalone){
 62:     // Check being called/included inside another script
 63:     $document = '{bodyContent}';
 64: }
 65: $tryCurl = 0;
 66: 
 67: 
 68: ///////////////////////////////////////////////
 69: // LAST-DITCH EFFORT COMPATIBILITY FUNCTIONS //
 70: ///////////////////////////////////////////////
 71: // If any errors are encountered in the actual requirements check script itself
 72: // due to missing/disabled functions on the server itself, these functions will
 73: // print an appropriate message for the occasion.
 74: 
 75: /**
 76:  * Wrapper for die()
 77:  * 
 78:  * @global type $standalone
 79:  */
 80: function RIP(){
 81:     global $standalone;
 82:     if($standalone){
 83:         die();
 84:     }
 85: }
 86: 
 87: /**
 88:  * Error handler.
 89:  * 
 90:  * @global type $document
 91:  * @global array $totalFailure
 92:  * @global boolean $responding
 93:  * @global type $standalone
 94:  * @param type $no
 95:  * @param type $st
 96:  * @param type $fi
 97:  * @param type $ln
 98:  */
 99: function handleReqError($no, $st, $fi = Null, $ln = Null){
100:     global $document, $totalFailure, $responding, $standalone;
101:     $fatal = $no === E_ERROR;
102:     if($no === E_ERROR){ // Ignore warnings...
103:         $responding = true;
104:         echo strtr($document, array(
105:             '{headerContent}' => '',
106:             '{bodyContent}' => str_replace('{scenario}', 'error', $totalFailure[0]."Error [$no]: $st $fi L$ln".$totalFailure[1])
107:         ));
108:         RIP();
109:     }
110: }
111: 
112: /**
113:  * Exception handler.
114:  *
115:  * @global type $document
116:  * @global array $totalFailure
117:  * @global boolean $responding
118:  * @global type $standalone
119:  * @param type $e
120:  */
121: function handleReqException($e){
122:     global $document, $totalFailure, $responding, $standalone;
123:     $responding = true;
124:     $message = 'Exception: "'.$e->getMessage().'" in '.$e->getFile().' L'.$e->getLine()."\n";
125: 
126:     foreach($e->getTrace() as $stackLevel){
127:         $message .= $stackLevel['file'].' L'.$stackLevel['line'].' ';
128:         if($stackLevel['class'] != ''){
129:             $message .= $stackLevel['class'];
130:             $message .= '->';
131:         }
132:         $message .= $stackLevel['function'];
133:         $message .= "();\n";
134:     }
135:     $message = str_replace('{scenario}', 'uncaught exception', $totalFailure[0].$message.$totalFailure[1]);
136:     echo strtr($document, array(
137:         '{headerContent}' => '',
138:         '{bodyContent}' => $message
139:     ));
140: 
141:     RIP();
142: }
143: 
144: /**
145:  * Shutdown function (for fatal errors, i.e. call to undefined function)
146:  * 
147:  * @global type $document
148:  * @global array $totalFailure
149:  * @global boolean $responding
150:  * @global type $standalone
151:  */
152: function reqShutdown(){
153:     global $document, $totalFailure, $responding, $standalone;
154:     $error = error_get_last();
155:     if($error != null && !$responding){
156:         $errno = $error["type"];
157:         $errfile = $error["file"];
158:         $errline = $error["line"];
159:         $errstr = $error["message"];
160:         $errtype = ($errno == E_PARSE ? 'parse' : 'fatal').' error';
161:         $message = "PHP $errtype [$errno]: $errstr in $errfile L$errline";
162:         $message = str_replace('{scenario}', $errtype, $totalFailure[0].$message.$totalFailure[1]);
163:         echo strtr($document, array(
164:             '{headerContent}' => '',
165:             '{bodyContent}' => $message
166:         ));
167:     }
168: }
169: 
170: /**
171:  * Throws an exception when encountering an error for easier handling.
172:  * 
173:  * @param type $no
174:  * @param type $st
175:  * @param type $fi
176:  * @param type $ln
177:  * @throws Exception
178:  */
179: function exceptionForError($no, $st, $fi = Null, $ln = Null){
180:     throw new Exception("Error [$no]: $st $fi L$ln");
181: }
182: 
183: /////////////////////
184: // EXTRA FUNCTIONS //
185: /////////////////////
186: 
187: /**
188:  * Attempt to query a host name's DNS record.
189:  * 
190:  * @param type $hostname
191:  * @return boolean
192:  */
193: function checkDNS($hostname) {
194:     if(function_exists('dns_check_record')) {
195:         return (integer) @dns_check_record($hostname);
196:     } else {
197:         return 0;
198:     }
199: }
200: 
201: /**
202:  * Test the consistency of the $_SERVER global.
203:  *
204:  * This function, based on the similarly-named function of the Yii requirements
205:  * check, validates several essential elements of $_SERVER
206:  *
207:  * @author Qiang Xue <qiang.xue@gmail.com>
208:  * @link http://www.yiiframework.com/
209:  * @copyright Copyright &copy; 2008-2011 Yii Software LLC
210:  * @license http://www.yiiframework.com/license/
211:  * @parameter string $thisFile
212:  * @return string
213:  */
214: function checkServerVar($thisFile = null){
215:     $vars = array('HTTP_HOST', 'SERVER_NAME', 'SERVER_PORT', 'SCRIPT_NAME', 'SCRIPT_FILENAME', 'PHP_SELF', 'HTTP_ACCEPT', 'HTTP_USER_AGENT');
216:     $missing = array();
217:     foreach($vars as $var){
218:         if(!isset($_SERVER[$var]))
219:             $missing[] = $var;
220:     }
221:     if(!empty($missing))
222:         return installer_tr('$_SERVER does not have {vars}.', array('{vars}' => implode(', ', $missing)));
223:     if(empty($thisFile))
224:         $thisFile = __FILE__;
225: 
226:     if(realpath($_SERVER["SCRIPT_FILENAME"]) !== realpath($thisFile))
227:         return installer_t('$_SERVER["SCRIPT_FILENAME"] must be the same as the entry script file path.');
228: 
229:     if(!isset($_SERVER["REQUEST_URI"]) && isset($_SERVER["QUERY_STRING"]))
230:         return installer_t('Either $_SERVER["REQUEST_URI"] or $_SERVER["QUERY_STRING"] must exist.');
231: 
232:     if(!isset($_SERVER["PATH_INFO"]) && strpos($_SERVER["PHP_SELF"], $_SERVER["SCRIPT_NAME"]) !== 0)
233:         return installer_t('Unable to determine URL path info. Please make sure $_SERVER["PATH_INFO"] (or $_SERVER["PHP_SELF"] and $_SERVER["SCRIPT_NAME"]) contains proper value.');
234: 
235:     return '';
236: }
237: 
238: /**
239:  * Tells if the directory is within the open_basedir restriction
240:  *
241:  * @param type $path
242:  * @return int
243:  */
244: function isAllowedDir($path) {
245:     $basedir = trim(ini_get('open_basedir'));
246:     if($allowCwd = empty($basedir))
247:         return 1;
248:     $basedirs = explode(PATH_SEPARATOR,$basedir);
249:     foreach($basedirs as $dir){
250:         if(empty($dir))
251:             continue;
252:         if(strpos($path,$dir) !== false){
253:             $allowCwd = 1;
254:             break;
255:         }
256:     }
257:     return $allowCwd;
258: }
259: 
260: /**
261:  * Attempt to access a remote URL
262:  *
263:  * @global bool $tryCurl
264:  * @param string $url
265:  * @return bool Whether access succeeded
266:  */
267: function tryGetRemote($url) {
268:     global $tryCurl;
269:     if($tryCurl || !(bool) ($response = @file_get_contents($url))){
270:         // Function file_get_contents not available, or failed:
271:         $ch = @curl_init($url);
272:         if(!(bool) $ch)
273:             return 0;
274:         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
275:         curl_setopt($ch, CURLOPT_POST, 0);
276:         $response = @curl_exec($ch);
277:         curl_close($ch);
278:     }
279:     return (int) (bool) $response;
280: }
281: 
282: // Set error handlers
283: if(!$returnArray){
284:     set_error_handler('handleReqError');
285:     set_exception_handler('handleReqException');
286:     register_shutdown_function('reqShutdown');
287: }
288: /////////////////////////////////
289: // X2Engine Requirements Check //
290: /////////////////////////////////
291: 
292: // Set scenario: "Cannot {scenario} X2Engine"
293: if(!isset($scenario))
294:     $scenario = 'install';
295: 
296: // Get PHP info
297: ob_start();
298: phpinfo();
299: $pi = ob_get_contents();
300: preg_match('%(<style[^>]*>.*</style>)%ms',$pi,$phpInfoStyle);
301: preg_match('%<body>(.*)</body>%ms',$pi,$phpInfoContent);
302: ob_end_clean();
303: if(count($phpInfoStyle))
304:     $phpInfoStyle = $phpInfoStyle[1];
305: else
306:     $phpInfoStyle = '';
307: if(count($phpInfoContent))
308:     $phpInfoContent = $phpInfoContent[1];
309: else
310:     $phpInfoStyle = '';
311: 
312: $phpInfoStyle .= '<style>
313: .hidden {display: none;}
314: </style>';
315: 
316: // Declare the function since the script is not being used from within the installer
317: if(!function_exists('installer_t')){
318:     function installer_t($msg){
319:         return $msg;
320:     }
321: 
322: }
323: if(!function_exists('installer_tr')) {
324:     function installer_tr($msg,$params = array()){
325:         return strtr($msg,$params);
326:     }
327: }
328: 
329: $canInstall = True;
330: $curl = true; //
331: $tryAccess = true; // Attempt to access the internet from the web server.
332: $reqMessages = array_fill_keys(array(1, 2, 3), array()); // Severity levels
333: $requirements = array_fill_keys(array('functions','classes','extensions','environment'),array());
334: $rbm = installer_t("required but missing");
335: 
336: // Sanity check:
337: if(!(@function_exists('function_exists') && @function_exists('extension_loaded')))
338:     throw new Exception(installer_t('The functions function_exist and/or extension_loaded are unavailable!').' '.installer_t('The requirements check script itself cannot run.'));
339: 
340: //////////////////////////////////////////////
341: // TOP PRIORITY: BIG IMPORTANT REQUIREMENTS //
342: //////////////////////////////////////////////
343: // Check for a mismatch in directory ownership. Skip this step on Windows
344: // and systems where posix functions are unavailable; in such cases there's no
345: // reliable way to get the UID of the actual running process.
346: $requirements['environment']['filesystem_ownership'] = 1;
347: $uid = array_fill_keys(array('{id_own}', '{id_run}'), null);
348: $uid['{id_own}'] = fileowner(realpath(dirname(__FILE__)));
349: if($requirements['extensions']['posix'] = function_exists('posix_geteuid')){
350:     $uid['{id_run}'] = posix_geteuid();
351:     if($uid['{id_own}'] !== $uid['{id_run}']){
352:         $reqMessages[3][] = strtr(installer_t("PHP is running with user ID={id_run}, but this directory is owned by the system user with ID={id_own}."), $uid);
353:         $requirements['environment']['filesystem_ownership'] = 0;
354:     }
355: } else {
356:     $reqMessages[1][] = installer_t('The requirements check script could not determine if local files have correct ownership because the "posix" extension is not available.');
357: }
358: 
359: $requirements['environment']['filesystem_permissions'] = 1;
360: // Check that the directory is writable. Print an error message one way or another.
361: if(!is_writable(dirname(__FILE__))){
362:     $reqMessages[3][] = installer_t("This directory is not writable by PHP processes run by the webserver.");
363:     $requirements['environment']['filesystem_permissions'] = 0;
364: }
365: if(!is_writable(__FILE__)) {
366:     $reqMessages[3][] = installer_t("Permissions and/or ownership of uploaded files do not permit PHP processes run by the webserver to write files.");
367:     $requirements['environment']['filesystem_permissions'] = 0;
368: }
369: 
370: 
371: 
372: 
373: // Check that the directive open_basedir is not arbitrarily set to some restricted 
374: // jail directory off in god knows where
375: $requirements['environment']['open_basedir'] = 1;
376: if(!empty($basedir)){
377:     if(!isAllowedDir(dirname(__FILE__))) {
378:         $reqMessages[3][] = installer_t('The base directory configuration directive is set, and it does not include the current working directory.');
379:         $requirements['environment']['open_basedir'] = 0;
380:     }
381: }
382: 
383: // Check PHP version
384: $requirements['environment']['php_version'] = 1;
385: if(!version_compare(PHP_VERSION, "5.3.0", ">=")){
386:     $reqMessages[3][] = installer_t("Your server's PHP version").': '.PHP_VERSION.'; '.installer_t("version 5.3 or later is required");
387:     $requirements['environment']['php_version'] = 0;
388: }
389: // Check $_SERVER variable meets requirements of Yii
390: $requirements['environment']['php_server_superglobal'] = 0;
391: if($mode == 'web'){
392:     if(($message = checkServerVar($thisFile)) !== ''){
393:         $reqMessages[3][] = installer_t($message);
394:     }else{
395:         $requirements['environment']['php_server_superglobal'] = 1;
396:     }
397: }
398: 
399: // Check for existence of Reflection class
400: $requirements['extensions']['pcre'] = 0;
401: $requirements['environment']['pcre_version'] = 0;
402: if(!($requirements['classes']['Reflection']=class_exists('Reflection', false))){
403:     $reqMessages[3][] = '<a href="http://php.net/manual/class.reflectionclass.php">PHP reflection class</a>: '.$rbm;
404: }else if($requirements['extensions']['pcre']=extension_loaded("pcre")){
405:     // Check PCRE library version
406:     $pcreReflector = new ReflectionExtension("pcre");
407:     ob_start();
408:     $pcreReflector->info();
409:     $pcreInfo = ob_get_clean();
410:     $matches = array();
411:     preg_match("/([\d\.]+) \d{4,}-\d{1,2}-\d{1,2}/", $pcreInfo, $matches);
412:     $thisVer = $matches[1];
413:     $reqVer = '7.4';
414:     if(!($requirements['environment']['pcre_version'] = version_compare($thisVer, $reqVer) >= 0)){
415:         $reqMessages[3][] = strtr(installer_t("The version of the PCRE library included in this build of PHP is {thisVer}, but {reqVer} or later is required."), array('{thisVer}' => $thisVer, '{reqVer}' => $reqVer));
416:     }
417: }else{
418:     $reqMessages[3][] = '<a href="http://www.php.net/manual/book.pcre.php">PCRE extension</a>: '.$rbm;
419: }
420: // Check for SPL extension
421: if(!($requirements['extensions']['SPL']=extension_loaded("SPL"))){
422: 
423:     $reqMessages[3][] = '<a href="http://www.php.net/manual/book.spl.php">SPL</a>: '.$rbm;
424: }
425: // Check for MySQL connecter
426: if(!($requirements['extensions']['pdo_mysql']=extension_loaded('pdo_mysql'))){
427:     $reqMessages[3][] = '<a href="http://www.php.net/manual/ref.pdo-mysql.php">PDO MySQL extension</a>: '.$rbm;
428: }
429: // Check for CType extension
430: if(!($requirements['extensions']['ctype']=extension_loaded('ctype'))){
431:     $reqMessages[3][] = '<a href="http://www.php.net/manual/book.ctype.php">CType extension</a>: '.$rbm;
432: }
433: // Check for multibyte-string extension
434: if(!($requirements['extensions']['mbstring']=extension_loaded('mbstring'))){
435:     $reqMessages[3][] = '<a href="http://www.php.net/manual/book.mbstring.php">Multibyte string extension</a>: '.$rbm;
436: }
437: // Check for JSON extension:
438: if(!($requirements['extensions']['json']=extension_loaded('json'))){
439:     $reqMessages[3][] = '<a href="http://www.php.net/manual/function.json-decode.php">json extension</a>: '.$rbm;
440: }
441: // Check for hash:
442: if(!($requirements['extensions']['hash']=extension_loaded('hash'))){
443:     $reqMessages[3][] = '<a href="http://www.php.net/manual/book.hash.php">HASH Message Digest Framework</a>: '.$rbm;
444: } else {
445:     $algosRequired = array('sha512');
446:     $algosAvail = hash_algos();
447:     $algosNotAvail = array_diff($algosRequired,$algosAvail);
448:     if(!empty($algosNotAvail))
449:         $reqMessages[3][] = installer_t('Some hashing algorithms required for software updates are missing on this server:').' '.implode(', ',$algosNotAvail);
450: }
451: 
452: // Check the session save path:
453: $ssp = ini_get('session.save_path');
454: if(!is_writable($ssp)){
455:     $reqMessages[3][] = strtr(installer_t('The path defined in session.save_path ({ssp}) is not writable.'), array('{ssp}' => $ssp));
456: }
457: 
458: // Miscellaneous functions:
459: $requiredFunctions = array(
460:     'php_sapi_name',
461:     'mb_regex_encoding',
462:     'getcwd',
463:     'chmod',
464:     'hash_algos',
465:     'mt_rand',
466:     'md5'
467: );
468: $missingFunctions = array();
469: foreach($requiredFunctions as $function)
470:     if(!($requirements['functions'][$function]=function_exists($function)))
471:         $missingFunctions[] = $function;
472: if(count($missingFunctions))
473:     $reqMessages[3][] = installer_t('The following required PHP function(s) is/are missing or disabled: ').implode(', ',$missingFunctions);
474: // Check for the permissions to run chmod on files owned by the web server:
475: if(!in_array('chmod', $missingFunctions)) {
476:     set_error_handler('exceptionForError');
477:     try{
478:         // Attempt to change the permissions of the current file and then change them back again
479:         $fp = fileperms(__FILE__); // original permissions
480:         chmod(__FILE__,octdec(100700));
481:         chmod(__FILE__,$fp);
482:         $requirements['environment']['chmod'] = 1;
483:     }catch (Exception $e){
484:         $reqMessages[3][] = installer_t('PHP scripts are not permitted to run the function "chmod".');
485:         $requirements['environment']['chmod'] = 0;
486:     }
487:     restore_error_handler();
488: }
489: 
490: ///////////////////////////////////////////////////////////
491: // MEDIUM-PRIORITY: IMPORTANT FUNCTIONALITY REQUIREMENTS //
492: ///////////////////////////////////////////////////////////
493: // Check remote access methods
494: $curl = ($requirements['extensions']['curl']=extension_loaded("curl")) && function_exists('curl_init') && function_exists('curl_exec');
495: if(!$curl){
496:     $curlMissingIssues = array(
497:         installer_t('Time zone widget will not work'),
498:         installer_t('Google integration will not work'),
499:         installer_t('Built-in error reporter will not work'),
500:         installer_t('API web hooks (and thus, Zapier integration) will not work'),
501:         installer_t('Twitter integration will not work')
502:     );
503:     $reqMessages[2][] = '<a href="http://php.net/manual/book.curl.php">cURL</a>: '.$rbm.'. '.installer_t('This will result in the following issues:').'<ul><li>'.implode('</li><li>', $curlMissingIssues).'</li></ul>'.installer_t('Furthermore, please note: without this extension, the requirements check script could not check the outbound internet connection of this server.');
504: }
505: 
506: if(!(bool) ($requirements['environment']['allow_url_fopen']=@ini_get('allow_url_fopen'))){
507:     if(!$curl){
508:         $tryAccess = false;
509:         $reqMessages[2][] = installer_t('The PHP configuration option "allow_url_fopen" is disabled in addition to the CURL extension missing. This means there is no possible way to make outbound HTTP/HTTPS requests.')
510:             .' '.installer_t('Software updates will have to be performed using the "offline" method, and Google integration will not work.');
511:     } else
512:         $reqMessages[1][] = installer_t('The PHP configuration option "allow_url_fopen" is disabled. CURL will be used for making all HTTP requests during updates.');
513: }
514: 
515: // Check memory allocation limits
516: $maxMem = ini_get('memory_limit');
517: if(!empty($maxMem) && preg_match('/(\d+)([BKMG])/i',$maxMem,$match)) {
518:     $multiplier = array(
519:         'b' => 1,
520:         'k' => 1024,
521:         'm' => 1048576,
522:         'g' => 1073741824
523:     );
524:     $maxBytes = ((integer)$match[1])*$multiplier[strtolower($match[2])];
525: } else {
526:     $maxBytes = (integer) $maxMem;
527: }
528: if((bool)((int)$maxBytes+1) && $maxBytes <= 33554432) {
529:     $reqMessages[2][] = installer_t('The memory limit is set to 32 megabytes or lower in the PHP configuration. Please consider raising this limit. X2Engine may otherwise encounter fatal runtime errors.');
530: }
531: 
532: ///////////////////////
533: // NETWORK DIAGNOSIS //
534: ///////////////////////
535: 
536: // Re-usable messages for network diagnosis:
537: $updateMethodMsg = installer_t('Software updates will have to be performed using the "offline" method.');
538: $googleIntegrationMsg = installer_t('Google integration will not work.');
539: $tmpProblemMsg = installer_t('This may be a temporary problem.');
540: $cutOffMsg = installer_t('This server is effectively cut off from the internet.');
541: $firewallMsg = installer_t('This is likely because the server is behind a firewall that is preventing outbound HTTP/HTTPS requests.');
542: 
543: // Defaults and presets:
544: $tryCurl = !$requirements['environment']['allow_url_fopen'];
545: $requirements['environment']['updates_connection'] = 0;
546: $requirements['environment']['outbound_connection'] = 0;
547: 
548: // Full network diagnosis:
549: if($tryAccess){
550:     // There exists one remote access method, so it's worth trying. 
551:     // 
552:     // Check outbound connection:
553:     if($requirements['environment']['outbound_connection'] = checkDNS('google.com')){
554:         // At least DNS is working, and at least for google.
555:         if($requirements['environment']['outbound_connection'] = tryGetRemote('http://www.google.com')){
556:             // Can connect to Google OK. Can connect to the updates server?
557:             if($requirements['environment']['updates_connection'] = checkDNS('x2planet.com')){
558:                 if(!($requirements['environment']['updates_connection'] = tryGetRemote('https://x2planet.com/installs/registry/reqCheck'))){
559:                     // 
560:                     $reqMessages[2][] = installer_t('Could not reach the updates server from this web server.')
561:                             .' '.$firewallMsg
562:                             .' '.$updateMethodMsg
563:                             .' '.$tmpProblemMsg;
564:                 }
565:             }else{
566:                 // No DNS for update server.
567:                 $reqMessages[2][] = installer_t('The DNS record associated with the updates server is not available on this web server.')
568:                         .' '.$updateMethodMsg
569:                         .' '.$tmpProblemMsg;
570:             }
571:         } else {
572:             // Can resolve DNS but can't make web request.
573:             $reqMessages[2][] = $cutOffMsg
574:                     .' '.$firewallMsg
575:                     .' '.installer_t('It is also posible that no outbound network route exists.')
576:                     .' '.$updateMethodMsg
577:                     .' '.$googleIntegrationMsg;
578:         }
579:     }else{
580:         // DNS failed for Google! There's no outbound connection period
581:         $reqMessages[2][] = $cutOffMsg
582:         .' '.installer_t('This is due to local DNS resolution failing.')
583:             .' '.$updateMethodMsg
584:             .' '.$googleIntegrationMsg;
585:     }
586: }
587: 
588: if(!function_exists('dns_check_record') && !$requirements['environment']['outbound_connection']) {
589:     $reqMessages[1][] = installer_t('Note: the function "dns_check_record" is not available on this server, so network diagnostic messages may not be accurate.');
590: }
591: 
592: 
593: 
594: // The ability to create network sockets, essential for SMTP-based email delivery:
595: if(!(bool) ($requirements['environment']['fsockopen'] = function_exists('fsockopen'))) {
596:     $reqMessages[2][] = installer_t('The function "fsockopen" is unavailable or has been disabled on this server. X2Engine will not be able to send email via SMTP.');
597: }
598: 
599: // Check the ability to make database backups during updates:
600: if(!(bool) ($canBackup = $requirements['functions']['proc_open'] = function_exists('proc_open'))) {
601:     $reqMessages[2][] = installer_t('The function proc_open is unavailable on this system. X2Engine will not be able to control the local cron table, or perform database backups, or automatically restore a database to its backup in the event of a failed update.');
602: }
603: $requirements['environment']['shell'] = $canBackup;
604: if($canBackup){
605:     try{
606:         // Test for the availability of mysqldump:
607:         $descriptor = array(
608:             0 => array('pipe', 'r'),
609:             1 => array('pipe', 'w'),
610:             2 => array('pipe', 'w'),
611:         );
612:         $testProc = proc_open('mysqldump --help', $descriptor, $pipes);
613:         $ret = proc_close($testProc);
614:         unset($pipes);
615:         
616:         if($ret === 0) {
617:             $prog = 'mysqldump';
618:         } else if($ret !== 0){
619:             $testProc = proc_open('mysqldump.exe --help', $descriptor, $pipes);
620:             $ret = proc_close($testProc);
621:             if($ret !== 0)
622:                 throw new Exception(installer_t('Unable to perform database backup; the "mysqldump" utility is not available on this system.'));
623:             else
624:                 $prog = 'mysqldump.exe';
625:         }
626:     }catch(Exception $e){
627:         $canBackup = false;
628:     }
629:     $canBackup = isset($prog);
630: }
631: if(!$canBackup && $requirements['functions']['proc_open']){
632:     $requirements['environment']['shell'] = 0;
633:     $reqMessages[1][] = installer_t('The "mysqldump" and "mysql" command line utilities are unavailable on this system. X2Engine will not be able to automatically make a backup of its database during software updates, or automatically restore its database in the event of a failed update.');
634: }
635: 
636: $giNotwork = installer_t('Google integration will not work.');
637: if(!function_exists('sys_get_temp_dir')){
638:     $message = installer_t('The function "sys_get_temp_dir" is unavailable.');
639:     if(isAllowedDir('/tmp')){
640:         if(!is_writable('/tmp')){
641:             $reqMessages[1][] = $msg.' '.installer_t('The directory "/tmp" is not writable.').' '.$giNotwork;
642:         }
643:     } else {
644:         $reqMessages[1][] = $msg.' '.installer_t('Use of the directory "/tmp" is not permitted on this system.').' '.$giNotwork;
645:     }
646: } else {
647:     $tmp = sys_get_temp_dir();
648:     if(!empty($tmp) && isAllowedDir($tmp)){
649:         if(!is_writable($tmp)){
650:             $reqMessages[1][] = installer_t('The system temporary directory, according to "sys_get_temp_dir", is not writable.').' '.$giNotwork;
651:         }
652:     }else{
653:         $reqMessages[1][] = installer_t('Usage of the system temporary directory, according to "sys_get_temp_dir", is either unknown or not permitted.').' '.$giNotwork;
654: 
655:     }
656: }
657: 
658: ////////////////////////////////////////////////////////////
659: // LOW PRIORITY: MISCELLANEOUS FUNCTIONALITY REQUIREMENTS //
660: ////////////////////////////////////////////////////////////
661: // Check encryption methods
662: if(!($requirements['extensions']['openssl']=extension_loaded('openssl') && $requirements['extensions']['mcrypt']=extension_loaded('mcrypt'))) {
663:     $reqMessages[1][] = installer_t('The "openssl" and "mcrypt" libraries are not available. If any application credentials (i.e. email account passwords) are entered into X2Engine, they  will be stored in the database in plain text (without any encryption whatsoever). Thus, if the database is ever compromised, those passwords will be readable by unauthorized parties.');
664: }
665: 
666: // Check for Zip extension
667: if(!($requirements['extensions']['zip']=extension_loaded('zip'))){
668:     $reqMessages[1][] = '<a href="http://php.net/manual/book.zip.php">Zip</a>: '.$rbm.'. '.installer_t('This will result in the inability to import and export custom modules.');
669: }
670: // Check for fileinfo extension
671: if(!($requirements['extensions']['fileinfo']=extension_loaded('fileinfo'))){
672:     $reqMessages[1][] = '<a href="http://php.net/manual/book.fileinfo.php">Fileinfo</a>: '.$rbm.'. '.installer_t('Image previews and MIME info for uploaded files in the media module will not be available.');
673: }
674: // Check for GD exension
675: if(!($requirements['extensions']['gd']=extension_loaded('gd'))){
676:     $reqMessages[1][] = '<a href="http://php.net/manual/book.image.php">GD</a>: '.$rbm.'. '.installer_t('Security captchas will not work, and the media module will not be able to detect or display the dimensions of uploaded images.');
677: }
678: 
679: // Check for SSH2 extension
680: if(!($requirements['extensions']['ssh2']=extension_loaded('ssh2'))){
681:     $reqMessages[1][] = '<a href="http://www.php.net/manual/book.ssh2.php">ssh2 extension</a>: '.$rbm.'. '.installer_t('The FileUtil class needs the SSH2 extension to use SSH as a file operation method.');
682: }
683: if(!($requirements['extensions']['iconv']=extension_loaded('iconv'))){
684:     $reqMessages[1][] = '<a href="http://www.php.net/manual/book.iconv.php">iconv extension</a>: '.$rbm.'. '.installer_t('A number of components require the iconv module for encoding and will not function properly.');
685: }
686: 
687: // Determine if there are messages to show and if installation is even possible
688: $hasMessages = false;
689: foreach($reqMessages as $severity=>$messages) {
690:     if((bool)count($messages))
691:         $hasMessages = true;
692: }
693: $canInstall = !(bool) count($reqMessages[3]);
694: 
695: ///////////////////////////////
696: // END OF REQUIREMENTS CHECK //
697: ///////////////////////////////
698: 
699: ////////////////////
700: // COMPOSE OUTPUT //
701: ////////////////////
702: $output = '';
703: 
704: if(!$canInstall){
705:     $output .= '<div style="width: 100%; text-align:center;"><h1>'.installer_t("Cannot $scenario X2Engine")."</h1></div>\n";
706:     $output .= "<strong>".installer_t('Unfortunately, your server does not meet the minimum system requirements;')."</strong><br />";
707: }else if($hasMessages){
708:     $output .= '<div style="width: 100%; text-align:center;"><h1>'.installer_t('Note the following:').'</h1></div>';
709: }else if($standalone){
710:     $output .= '<div style="width: 100%; text-align:center;"><h1>'.installer_t('This webserver can run X2Engine!').'</h1></div>';
711: }
712: 
713: $severityClasses = array(
714:     1 => 'minor',
715:     2 => 'major',
716:     3 => 'critical'
717: );
718: $severityStyles = array(
719:     1 => 'color:black',
720:     2 => 'color:#CF5A00',
721:     3 => 'color: #DD0000'
722: );
723: 
724: if($hasMessages){
725:     $output .= "\n<ul>";
726:     foreach($reqMessages as $severity => $messages){
727:         foreach($messages as $message){
728:             $output .= "<li style=\"{$severityStyles[$severity]}\">$message</li>";
729:         }
730:     }
731:     $output .= "</ul>\n";
732:     $output .= "<div style=\"text-align:center;\">Severity legend: ";
733:     foreach($severityClasses as $severity => $class) {
734:         $output .= "<span style=\"{$severityStyles[$severity]}\">$class</span>&nbsp;";
735:     }
736:     $output .= "<br />\n";
737:     if($canInstall)
738:         $output .= '<br />'.installer_t("All other essential requirements were met.").'&nbsp;';
739:     $output .= '</div><br />';
740: }
741: 
742: if($standalone){
743:     $imgData = 'iVBORw0KGgoAAAANSUhEUgAAAGkAAAAfCAYAAADk+ePmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADMlJREFUeNrs'.
744:             'W3lwVGUS/82RZBISyMkRwhESIISjEBJAgWRQbhiuci3AqsUVarfcWlZR1xL+2HJry9oqdNUtj0UFQdSwoELCLcoKBUgOi3AkkkyCYi4SSELOSTIzyWz3N/Ne3nszCVnd2qHKNNU1'.
745:             '731nf91fd/++7wUdiI4cOTKIfp4hfoJ4NPrJ39RAnEn8hsViuaLzGOhMZGTk1Pj4eAwZMqRfRX6mtrY2VFRUoKSkhI1lNrIHsYFmzJwpGnS5XP1a8jMFmUxISEyEwWgML7p+PVPP'.
746:             'IS4hIQGurq5fFNtaW/Hujh2q9zdef/2+knHUyJEwmUyj2ZNGh0dE/OI8qLy8HMOHD5fXze+JtHvvNz0EBweDjSSs5g86c+Ys6uvrSFlxuHbtKjZt2oTKykrk5OQI4Tg2r1mzBm++'.
747:             '+SY2b96MnNxcXLvqbnfw4EFMnjIFIdSO29fX18NsNnMcF/14zClTJuPEiRPyu9mcLr/zPOnUXlq71WoV5dkXs2VZtm/fjhdeeEGU79y5U8jgDzL6Mw/VkYEoHyJ1Rqp4tpKCT548'.
748:             'iY0bNwojHTp0COWUQF0eGa+SgZhabTZqXw8O0xkZGVi/fj0p9ppoW8HKT08XXsH9Fy9eLPpwO1ubTZQz79q1C7GxsfLalf0kWWLJ02rr6pBLm2MRjeMPPbloTr3kSf7gSlJqakqK'.
749:             'eK4nZbi6XEgkxZuCgtw7nATkZ/4tsZZg0qRJiKTQzMZKm5uGivIK0e8QeVVdbR2VzRXvCWPGiP6lpOizZ84I71m3dq2YT6rjdhHh4bIsPIeyLnbYMGFERlnKfv9v9rsnSUimoqKS'.
750:             'EyRxEOrq6oU8VZVVwls4X5rIqzgErVy1Cv+kXc27K4WMW0W7nxW5YuVKGZmyB0rr4ecFCxeqoC3X5eXlqdop63helkUgLDLM7t27sXLlKr/piGc1UKh4iVEE76Sfy699/A0iBgYj'.
751:             'elDwPdtyDikoKBC/Tc1NWEjKDAsLE4Jdzs93ly1YCKPRAIfTKZBOBBmMhZaeuX3N7du4fPkympqahPECjEaM9KzHZArGxW8u4vbtGsTEDBbti4uKEBYaJp5HKtbNctwoLZVl4TKj'.
752:             'MQDFxUVYunTp/0Q/P4VrqqvBh1nXHAoTP5feOZCHzDNFCA0JxG9WPABL2rhe2xcWFqKqqgoLFiy4bw+Uez/8EJYVK4S3+osYKLnDXZdvVy7+sZaSrQMGgx4GvU5wUnyMV7t/5/2A'.
753:             'Q18XYUjUAPx4qxE7My+h8nYTfrtmeo+T2yj5J09I7nFuf9O3FBKXL7dg6NBhfpWRHcoNwV2+IXheYRXe+TRPeEdocCAGBAfg2ccfxNTx3VdH331fi7f25yJ1Yizyi25BT4a0Ozph'.
754:             'a3fgVm0z3iYP+/rbm2i22eU+YTTevJTReOrRsaq5z58/j9ra2h4FnjNnDqKjo1FEIYtZIg5PISEh8ruyXuqjJZ6rrKwM5cQSjU9KQpKHH5o9W4yRnZMt6qRypszMTLkPh8xp06ap'.
755:             'xpbqeV6eX9vHF62ifNtTVurVk9YtmoiC0hpcKq6Wy/YevYLxo+YhKNCI8ppG/CMjB7HRYbCS14WGBJEhA5GSTMk8fTzWbvscza1u4xgN+u5Q0uHE8QulOJdfhoyXV2NoVKhbcefO'.
756:             'UQ4o7nEhycnJBNmjcP36dRzOypLLdfSPw5JEynqpj0T5+ZewL2MfARTvzcBGqZg+HUnjkwRQUI5joPPauHHjxXOWQuG8OZJeeVWAG4mk+gkTJggjsX6z7mGkNavXwNnZ6RM46CVP'.
757:             '6olffOIh4UVymCIPyThRQL92fHjkKoVCHToFVKTfzi4MjQ7FH9fNwp4jl2HQ6RAeGiR4+OAwpE8bJb8zc/jMOFkgEn5P3qz1fdFOg7ROnfqCPPCOLLOq3tOH+fz5c3iLDsaSgVjB'.
758:             'rEiJpffOrk6f88jja8J2VlamSmfac05f1uaCy6f+BYBxe1LPg4SYjNiyfgZez8jtTmbkXaUV9RTa9ALNcf6JIyPcbW7HK08vBDkZrlprMHBAkNznb5vnY+KYaFwuvoU/7zgrlzeR'.
759:             'p7GxHM5OsSCJtm3bhrHj1OCDz1HOTqeqHSuWFXXk8GH8esMGWTFK4vXV0dnnX/v2de9c8gyG54GBge7t6nZJtDMU9+jD1zgq3XjmPnXqFB6ZP18gTi/lk8zafnv37vVs7G7qpPX3'.
760:             'ZAd9t7V75hkTh2Hp7ARVRwflHfac+kYbhpH3dNid+OvvH0ZQAOckBx5fPBEbLFPxq/nJMFP+mZQQg7b2drFnOCdJHBJkFMb2Ugi92+12FTucDrdMinZzPciUc0yJ1epV7/Ks76sv'.
761:             'vxSIjWk6hbTlFouY10nwng0vmJ6NAQHda/dx+lfKyeMEe8LcB7s+8KBmV699hEEorGnXJm0+L5YPs31AL6vN41B44w6FOad7yxG1dxDyo4U2kgdtsDyAkUMGotXmVoQlLVEoQafT'.
762:             'iTYdJEgrIcXDZ60UPgPkcceNjBI7iGVQSsH5qeDaNZUMywhtaXf4iBEj5Gc6TuCZLVvUSnG5xNhl5eXda1m9Gh0d9j5dyag9Sf3OIIdBw4ULF8R5qrTEijEJiV6bTduPQUSnIv9E'.
763:             'RkXhwQcf6jHEe24c7h0zTUEGLJgZj6yzJZ796TYU2QBrF0/G7Kkj0NzSClnV9KN06eraVnxyolCERFOQ0X0jEBSAFeYk8jy7WwaFUtgzvDYKhaj2jg6V8qIIQc2aNQvZ2dki8V+5'.
764:             'ckVV7/Ksj71MotjY4QRe2sXzsaNHcfzYMdU8zz//J8QnjPHh3d56WrZ8uTAS0/79+/Hi1m1eeUzbL0sBeiSAMZvQZO/AgXfxPbiipglf5dxU5RkmJ4W8xBGRaGltFR7hq29e4S3s'.
765:             '+DwfdxraqL1LcKDRgKfXzyIvc1HodIp2fdnZop0mni1ZukwOO58eOKCG3C54jc1Kk2SDj2kNBoPPOrmPgviC2DxvnnhmSJ+bmyPKvGTu49q0DBf65kltFOLeO3gFkYNCRA7S0msf'.
766:             'X8SLG2YSLNd71X1+2oqz+RWqstHDBmELnbdCQ4zCuMpdI9HWrVspdGjzoMOtYI2VIiIjYDbPw4kTx0UIamxoUNVzH1YcX/0wXbp0CUm0e5lmzJyByZMnCc+VPELqo81KvvTEyl2y'.
767:             'ZClyyJM55/Eve7c0F9dr++3Zs0dcdSmJ04FvO7ju7UktdAjd/lGuyC0l5XUCgg8KNaljc4MNxy5879X3/cyrOErlfJCV2JI2Hi//YT5MBKpaODyqdk23UjhU2ii/Kdlud7jbasIZ'.
768:             'l6WZzfIO/pJAgraevz3JNySnT8seFhERidjhcQgbONCrjxcI8OFJLnFHaMLiJUvkMxrfmvfmSRw5tGtjdOfTBuiDJ310vBBl1U0YHDnAHQqMeoLNHXg4NR6nc7+X2x2/cIMQXDQS'.
769:             'hrsvSfO+q8YX2T+oxkqIi6Rc4MCOz3IISXXH38fmj/PyJA4d/N1IG1qYvYAByc836IsWL6GD6icCFmvr09LSxWcL6dD6/nvvYhEplr/OeoEET5++5KQuafz0dJyh8e+SBynn7/Lh'.
770:             'SUUEMji3KonlCFYciL2BQw8x88BXxfi26DZiY8JQeaeZDqAmNLZ04KXfmckYg1BaXgtr2V25/Ssf5eCNZx+mfKPD259dVl0Fidtta7VgLfGFbHNLi8pKyjONRPzJgD1GpU+F/Cmp'.
771:             'qcIQVVWVXvX8yWPtuvU0bob7rEfI8ZoGPWr7aL9O+NKT+xzk8lztrMbuD3b1WC/R31991Wuc5557HrFxcf/djcMpAgn7ThWJBG8tq0fUoGDKR2146tEUJMaF425DIx57ZCyFLYM8'.
772:             'YIvNgbc+zceNigbcrGoUl7N9Yf4c4T6V955g+aLXVzul3Ct93IFJdSmpKXjyyY0+7/K0h9Te5vF1o8A8cdJE8bX4p9w46D1r87pxYATNnyoSPXdSSvrLrmykJI/ApaIqCnWhaKYQ'.
773:             'NyE+BptWPYA7tXUyXLz+Qz2+KaiB3elCOx1oOZytmDsWe49dpdBo6NNN7/vblqGWwkRNTTX0vbSLjomBTm8QIcXpsMtw2qGBrhXlZQRiAnusNxJ642ukGzduwGG3y4bhz+VjE8cK'.
774:             'eN7e3qGaR5pbOX5IyACEE2jhHCORso+yXimTL/IlJ1Ml9WMj3R05Oj6cP5apdi0peEBwiIinep1e/uVbA0ZZqjMUJc7AgAAvtNKbUGoY36nOI/0kE9/Ss2Uy6+tqn4gZrP7L1S6y'.
775:             'foOjqU8D2Qh62jxXLmro3t6v5Z9BfI9ot3c0sJFeamluXqXX68PDwyMoNhr6tXOfGOh2jQBZz+g8d16j+IxFbOY/wOgn/xJf9HY6nTfZQBaLJUunrPT88f7UfjX5nRr4f1NIL/8R'.
776:             'YABtitvxQEn6dgAAAABJRU5ErkJggg==';
777:     $output .= '<div style="display:block;float:none;margin-left:275px; width: 150px; display:inline-block"><img style="display:block;float:none;" src="data:image/png;base64,'.$imgData.'"><br />';
778:     $output .= '<a style="display:block;float:none; padding:0; color: #6A6AA8;font-family:monospace;font-weight:bold; text-decoration:none;" href="javascript:void(0);" onclick="showHidePhpInfo(this);">[ + phpinfo()]</a></div><br /><br />';
779:     $output .= "<div id=\"phpInfoContent\" class=\"hidden\"><div style=\"font-family:monospace;text-align:center\">PHP_SAPI == \"".
780:             PHP_SAPI."\"</div><br />$phpInfoContent</div>";
781:     $output .= '
782: <script type="text/javascript">
783: function showHidePhpInfo(elt) {
784:     var content = document.getElementById("phpInfoContent");
785:     if (content.getAttribute("class") == "hidden") {
786:         elt.innerHTML = "[ - phpinfo()]";
787:         content.setAttribute("class","");
788:     } else {
789:         elt.innerHTML = "[ + phpinfo()]";
790:         content.setAttribute("class","hidden");
791:     }
792: }
793: </script>';
794: }
795: 
796: /////////
797: // FIN //
798: /////////
799: if(!$returnArray){
800:     echo strtr($document, array(
801:         '{headerContent}' => $phpInfoStyle,
802:         '{bodyContent}' => $output
803:     ));
804:     $responding = true; // We made it! No need to perform the shutdown function for fatal errors.
805:     restore_error_handler();
806:     restore_exception_handler();
807: }else{
808:     return compact('requirements','reqMessages','canInstall','hasMessages');
809: }
810: ?>
811: 
X2CRM Documentation API documentation generated by ApiGen 2.8.0