<?php class PhpPsInfo { protected $login; protected $password; const DEFAULT_PASSWORD = 'prestashop'; const DEFAULT_LOGIN = 'prestashop'; const TYPE_OK = true; const TYPE_ERROR = false; const TYPE_WARNING = null; const TYPE_SUCCESS_CLASS = 'table-success'; const TYPE_ERROR_CLASS = 'table-danger'; const TYPE_INFO_CLASS = 'table-info'; const TYPE_WARNING_CLASS = 'table-warning'; protected $requirements = [ 'versions' => [ 'php' => '7.1', 'mysql' => '5.5', ], 'extensions' => [ 'bcmath' => false, 'curl' => true, 'dom' => true, 'fileinfo' => true, 'gd' => true, 'iconv' => true, 'imagick' => false, 'intl' => true, 'json' => true, 'mbstring' => true, 'memcache' => false, 'memcached' => false, 'openssl' => true, 'pdo_mysql' => true, 'simplexml' => true, 'zip' => true, ], 'config' => [ 'allow_url_fopen' => true, 'expose_php' => false, 'file_uploads' => true, 'max_input_vars' => 1000, 'memory_limit' => '64M', 'post_max_size' => '16M', 'register_argc_argv' => false, 'set_time_limit' => true, 'short_open_tag' => false, 'upload_max_filesize' => '4M', ], 'directories' => [ 'cache_dir' => 'var/cache', 'log_dir' => 'var/logs', 'img_dir' => 'img', 'mails_dir' => 'mails', 'module_dir' => 'modules', 'translations_dir' => 'translations', 'customizable_products_dir' => 'upload', 'virtual_products_dir' => 'download', 'override_dir' => 'override', 'config_sf2_dir' => 'app/config', 'translations_sf2' => 'app/Resources/translations', ], 'apache_modules' => [ 'mod_alias' => false, 'mod_env' => false, 'mod_headers' => false, 'mod_rewrite' => false, ], ]; protected $recommended = [ 'versions' => [ 'php' => '8.1', 'mysql' => '8.0', ], 'extensions' => [ 'bcmath' => true, 'curl' => true, 'dom' => true, 'fileinfo' => true, 'gd' => true, 'iconv' => true, 'imagick' => true, 'intl' => true, 'json' => true, 'mbstring' => true, 'memcache' => false, 'memcached' => true, 'openssl' => true, 'pdo_mysql' => true, 'simplexml' => true, 'zip' => true, ], 'config' => [ 'allow_url_fopen' => true, 'expose_php' => false, 'file_uploads' => true, 'max_input_vars' => 5000, 'memory_limit' => '256M', 'post_max_size' => '128M', 'register_argc_argv' => false, 'set_time_limit' => true, 'short_open_tag' => false, 'upload_max_filesize' => '128M', ], 'apache_modules' => [ 'mod_alias' => false, 'mod_env' => true, 'mod_headers' => true, 'mod_rewrite' => true, ], ]; /** * Set up login and password with parameter or * you can set server env vars: * - PS_INFO_LOGIN * - PS_INFO_PASSWORD * * @param string $login Login * @param string $password Password * */ public function __construct($login = self::DEFAULT_LOGIN, $password = self::DEFAULT_PASSWORD) { if (!empty($_SERVER['PS_INFO_LOGIN'])) { $this->login = $_SERVER['PS_INFO_LOGIN']; } if (!empty($_SERVER['PS_INFO_PASSWORD'])) { $this->password = $_SERVER['PS_INFO_PASSWORD']; } $this->login = !empty($login) ? $login : $this->login; $this->password = !empty($password) ? $password : $this->password; } /** * Check authentication if not in cli and have a login */ public function checkAuth() { if (PHP_SAPI === 'cli' || empty($this->login) ) { return; } if (!isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_PW'] != $this->password || $_SERVER['PHP_AUTH_USER'] != $this->login ) { header('WWW-Authenticate: Basic realm="Authentification"'); header('HTTP/1.0 401 Unauthorized'); echo '401 Unauthorized'; exit(401); } } /** * Get versions data * * @return array */ public function getVersions() { $data = [ 'Web server' => [$this->getWebServer()], 'PHP Type' => [ strpos(PHP_SAPI, 'cgi') !== false ? 'CGI with Apache Worker or another webserver' : (strpos(PHP_SAPI, 'litespeed') !== false ? 'Litespeed (Better performance)' : 'Apache Module (low performance)') ], ]; $data['PHP Version'] = [ $this->requirements['versions']['php'], $this->recommended['versions']['php'], PHP_VERSION, version_compare(PHP_VERSION, $this->recommended['versions']['php'], '>=') ? self::TYPE_OK : ( version_compare(PHP_VERSION, $this->requirements['versions']['php'], '>=') ? self::TYPE_WARNING : self::TYPE_ERROR ) ]; if (!extension_loaded('mysqli') || !is_callable('mysqli_connect')) { $data['MySQLi Extension'] = [ true, true, 'Not installed', self::TYPE_ERROR, ]; } else { $data['MySQLi Extension'] = [ $this->requirements['versions']['mysql'], $this->recommended['versions']['mysql'], mysqli_get_client_info(), self::TYPE_OK, ]; } $data['Internet connectivity (Prestashop)'] = [ false, true, gethostbyname('www.prestashop.com') !== 'www.prestashop.com', gethostbyname('www.prestashop.com') !== 'www.prestashop.com', ]; return $data; } /** * Get php extensions data * * @return array */ public function getPhpExtensions() { $data = []; $vars = [ 'BCMath Arbitrary Precision Mathematics' => 'bcmath', 'Client URL Library (Curl)' => 'curl', 'Image Processing and GD' => 'gd', 'Image Processing (ImageMagick)' => 'imagick', 'Human Language and Character Encoding Support (Iconv)' => 'iconv', 'Internationalization Functions (Intl)' => 'intl', 'Memcache' => 'memcache', 'Memcached' => 'memcached', 'Multibyte String (Mbstring)' => 'mbstring', 'OpenSSL' => 'openssl', 'File Information (Fileinfo)' => 'fileinfo', 'JavaScript Object Notation (Json)' => 'json', 'PDO and MySQL Functions' => 'pdo_mysql', 'SimpleXML' => 'simplexml', ]; foreach ($vars as $label => $var) { $value = extension_loaded($var); $data[$label] = [ $this->requirements['extensions'][$var], $this->recommended['extensions'][$var], $value ]; } $vars = [ 'PHP-DOM and PHP-XML' => ['dom', 'DomDocument'], 'Zip' => ['zip', 'ZipArchive'], ]; foreach ($vars as $label => $var) { $value = class_exists($var[1]); $data[$label] = [ $this->requirements['extensions'][$var[0]], $this->recommended['extensions'][$var[0]], $value ]; } return $data; } /** * Get php config data * * @return array */ public function getPhpConfig() { $data = []; $vars = [ 'allow_url_fopen', 'expose_php', 'file_uploads', 'register_argc_argv', 'short_open_tag', ]; foreach ($vars as $var) { $value = (bool) ini_get($var); $data[$var] = [ $this->requirements['config'][$var], $this->recommended['config'][$var], $value ]; } $vars = [ 'max_input_vars', 'memory_limit', 'post_max_size', 'upload_max_filesize', ]; foreach ($vars as $var) { $value = ini_get($var); if ($this->toBytes($value) >= $this->toBytes($this->recommended['config'][$var])) { $result = self::TYPE_OK; } elseif ($this->toBytes($value) >= $this->toBytes($this->requirements['config'][$var])) { $result = self::TYPE_WARNING; } else { $result = self::TYPE_ERROR; } $data[$var] = [ $this->requirements['config'][$var], $this->recommended['config'][$var], $value, $result, ]; } $vars = [ 'set_time_limit', ]; foreach ($vars as $var) { $value = is_callable($var); $data[$var] = [ $this->recommended['config'][$var], $this->requirements['config'][$var], $value ]; } return $data; } /** * Check if directories are writable * * @return array */ public function getDirectories() { $data = []; foreach ($this->requirements['directories'] as $directory) { $directoryPath = getcwd() . DIRECTORY_SEPARATOR . trim($directory, '\\/'); $data[$directory] = file_exists($directoryPath) ? [is_writable($directoryPath)] : [null]; } return $data; } public function getServerModules() { $data = []; if ($this->getWebServer() !== 'Apache' || !function_exists('apache_get_modules')) { return $data; } $modules = apache_get_modules(); $vars = array_keys($this->requirements['apache_modules']); foreach ($vars as $var) { $value = in_array($var, $modules); $data[$var] = [ $this->requirements['apache_modules'][$var], $this->recommended['apache_modules'][$var], $value, ]; } return $data; } /** * Convert PHP variable (G/M/K) to bytes * Source: http://php.net/manual/fr/function.ini-get.php * * @param mixed $value * * @return integer */ public function toBytes($value) { if (is_numeric($value)) { return $value; } $value = trim($value); $val = (int) $value; switch (strtolower($value[strlen($value)-1])) { case 'g': $val *= 1024; // continue case 'm': $val *= 1024; // continue case 'k': $val *= 1024; } return $val; } /** * Transform value to string * * @param mixed $value Value * * @return string */ public function toString($value) { if ($value === true) { return 'Yes'; } elseif ($value === false) { return 'No'; } elseif ($value === null) { return 'N/A'; } return strval($value); } /** * Get html class * * @param array $data * @return string */ public function toHtmlClass(array $data) { if (count($data) === 1 && !is_bool($data[0])) { return self::TYPE_INFO_CLASS; } if (count($data) === 1 && is_bool($data[0])) { $result = $data[0]; } elseif (array_key_exists(3, $data)) { $result = $data[3]; } else { if ($data[2] >= $data[1]) { $result = self::TYPE_OK; } elseif ($data[2] >= $data[0]) { $result = self::TYPE_WARNING; } else { $result = self::TYPE_ERROR; } } if ($result === false) { return self::TYPE_ERROR_CLASS; } if ($result === null) { return self::TYPE_WARNING_CLASS; } return self::TYPE_SUCCESS_CLASS; } /** * Detect Web server * * @return string */ protected function getWebServer() { if (stristr($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false) { return 'Apache'; } elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) { return 'Lite Speed'; } elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'Nginx') !== false) { return 'Nginx'; } elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'lighttpd') !== false) { return 'lighttpd'; } elseif (stristr($_SERVER['SERVER_SOFTWARE'], 'IIS') !== false) { return 'Microsoft IIS'; } return 'Not detected'; } /** * Determines if a command exists on the current environment * Source: https://stackoverflow.com/questions/12424787/how-to-check-if-a-shell-command-exists-from-php * * @param string $command The command to check * * @return bool */ protected function commandExists($command) { $which = (PHP_OS == 'WINNT') ? 'where' : 'which'; $process = proc_open( $which . ' ' . $command, [ ['pipe', 'r'], //STDIN ['pipe', 'w'], //STDOUT ['pipe', 'w'], //STDERR ], $pipes ); if ($process !== false) { $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); return $stdout != ''; } return false; } } // Init render $info = new PhpPsInfo(); $info->checkAuth(); ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> <meta name="description" content=""/> <meta name="author" content=""/> <link rel="icon" href="../../../../favicon.ico"/> <title>PHP PrestaShop Info</title> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" /> <style> h1 {font-size:2rem;} </style> </head> <body> <nav class="navbar navbar-dark bg-dark flex-md-nowrap p-0 shadow"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">PHP PrestaShop Info</a> </nav> <div class="container-fluid"> <div class="row justify-content-md-center"> <main role="main" class="col-8"> <h1>General information & PHP/MySQL Version</h1> <div class="table-responsive"> <table class="table table-striped table-sm text-center"> <thead> <tr> <th class="text-left">#</th> <th>Required</th> <th>Recommended</th> <th>Current</th> </tr> </thead> <tbody> <?php foreach ($info->getVersions() as $label => $data) : ?> <?php if (count($data) === 1) : ?> <tr> <td class="text-left"><?php echo $label ?></td> <td class="<?php echo $info->toHtmlClass($data); ?>" colspan="3"><?php echo $info->toString($data[0]) ?></td> </tr> <?php else : ?> <tr> <td class="text-left"><?php echo $label ?></td> <td><?php echo $info->toString($data[0]) ?></td> <td><?php echo $info->toString($data[1]) ?></td> <td class="<?php echo $info->toHtmlClass($data); ?>"><?php echo $info->toString($data[2]) ?></td> </tr> <?php endif; ?> <?php endforeach; ?> </tbody> </table> </div> <h1>PHP Configuration</h1> <div class="table-responsive"> <table class="table table-striped table-sm text-center"> <thead> <tr> <th class="text-left">#</th> <th>Required</th> <th>Recommended</th> <th>Current</th> </tr> </thead> <tbody> <?php foreach ($info->getPhpConfig() as $label => $data) : ?> <tr> <td class="text-left"><?php echo $label ?></td> <td><?php echo $info->toString($data[0]) ?></td> <td><?php echo $info->toString($data[1]) ?></td> <td class="<?php echo $info->toHtmlClass($data); ?>"><?php echo $info->toString($data[2]) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <h1>PHP Extensions</h1> <div class="table-responsive"> <table class="table table-striped table-sm text-center"> <thead> <tr> <th class="text-left">#</th> <th>Required</th> <th>Recommended</th> <th>Current</th> </tr> </thead> <tbody> <?php foreach ($info->getPhpExtensions() as $label => $data) : ?> <tr> <td class="text-left"><?php echo $label ?></td> <td><?php echo $info->toString($data[0]) ?></td> <td><?php echo $info->toString($data[1]) ?></td> <td class="<?php echo $info->toHtmlClass($data); ?>"><?php echo $info->toString($data[2]) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <h1>Directories</h1> <div class="table-responsive"> <table class="table table-striped table-sm text-center"> <thead> <tr> <th class="text-left">#</th> <th>Is Writable</th> </tr> </thead> <tbody> <?php foreach ($info->getDirectories() as $label => $data) : ?> <tr> <td class="text-left"><?php echo $label ?></td> <?php if (null == $data[0]) : ?> <td class="<?php echo PhpPsInfo::TYPE_ERROR_CLASS; ?>">Directory not exists</td> <?php else : ?> <td class="<?php echo $info->toHtmlClass($data); ?>"><?php echo $info->toString($data[0]) ?></td> <?php endif; ?> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php if (count($info->getServerModules()) > 0): ?> <h1>Apache Modules</h1> <div class="table-responsive"> <table class="table table-striped table-sm text-center"> <thead> <tr> <th class="text-left">#</th> <th>Required</th> <th>Recommended</th> <th>Current</th> </tr> </thead> <tbody> <?php foreach ($info->getServerModules() as $label => $data) : ?> <tr> <td class="text-left"><?php echo $label ?></td> <td><?php echo $info->toString($data[0]) ?></td> <td><?php echo $info->toString($data[1]) ?></td> <td class="<?php echo $info->toHtmlClass($data); ?>"><?php echo $info->toString($data[2]) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <?php endif; ?> </main> </div> </div> <footer class="footer-copyright text-center py-3"> © <?php echo date('Y') ?> Copyright: <a href="https://prestashop.com/">PrestaShop</a> </footer> </body> </html>