diff --git a/.gitignore b/.gitignore index 6cd6c386..5fe1bb81 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ log/ run/ +cfg/mysql-5.5/*.cnf diff --git a/base/README.md b/base/README.md new file mode 100644 index 00000000..2841348f --- /dev/null +++ b/base/README.md @@ -0,0 +1,7 @@ +# Devilbox base configuration + +Those folders include the devilbox base configuration. + +Do not edit anything here! + +You can use the `cfg/` directory in the root folder to customize your configuration. diff --git a/bin/apache-2.2/fix-virtual-docroot.php b/base/bin/apache-2.2/fix-virtual-docroot.php similarity index 100% rename from bin/apache-2.2/fix-virtual-docroot.php rename to base/bin/apache-2.2/fix-virtual-docroot.php diff --git a/bin/apache-2.2/splitlogs.php b/base/bin/apache-2.2/splitlogs.php similarity index 100% rename from bin/apache-2.2/splitlogs.php rename to base/bin/apache-2.2/splitlogs.php diff --git a/bin/apache-2.4/fix-virtual-docroot.php b/base/bin/apache-2.4/fix-virtual-docroot.php similarity index 100% rename from bin/apache-2.4/fix-virtual-docroot.php rename to base/bin/apache-2.4/fix-virtual-docroot.php diff --git a/bin/apache-2.4/splitlogs.php b/base/bin/apache-2.4/splitlogs.php similarity index 100% rename from bin/apache-2.4/splitlogs.php rename to base/bin/apache-2.4/splitlogs.php diff --git a/etc/apache-2.2/00-defaults.conf b/base/etc/apache-2.2/00-defaults.conf similarity index 100% rename from etc/apache-2.2/00-defaults.conf rename to base/etc/apache-2.2/00-defaults.conf diff --git a/etc/apache-2.2/01-vhost-default.conf b/base/etc/apache-2.2/01-vhost-default.conf similarity index 100% rename from etc/apache-2.2/01-vhost-default.conf rename to base/etc/apache-2.2/01-vhost-default.conf diff --git a/etc/apache-2.2/02-vhost-mass.conf b/base/etc/apache-2.2/02-vhost-mass.conf similarity index 100% rename from etc/apache-2.2/02-vhost-mass.conf rename to base/etc/apache-2.2/02-vhost-mass.conf diff --git a/etc/apache-2.4/00-defaults.conf b/base/etc/apache-2.4/00-defaults.conf similarity index 100% rename from etc/apache-2.4/00-defaults.conf rename to base/etc/apache-2.4/00-defaults.conf diff --git a/etc/apache-2.4/01-vhost-default.conf b/base/etc/apache-2.4/01-vhost-default.conf similarity index 100% rename from etc/apache-2.4/01-vhost-default.conf rename to base/etc/apache-2.4/01-vhost-default.conf diff --git a/etc/apache-2.4/02-vhost-mass.conf b/base/etc/apache-2.4/02-vhost-mass.conf similarity index 100% rename from etc/apache-2.4/02-vhost-mass.conf rename to base/etc/apache-2.4/02-vhost-mass.conf diff --git a/www/config.php b/base/www/config.php similarity index 100% rename from www/config.php rename to base/www/config.php diff --git a/www/htdocs/_ajax_db.php b/base/www/htdocs/_ajax_db.php similarity index 100% rename from www/htdocs/_ajax_db.php rename to base/www/htdocs/_ajax_db.php diff --git a/www/htdocs/_ajax_vhost.php b/base/www/htdocs/_ajax_vhost.php similarity index 100% rename from www/htdocs/_ajax_vhost.php rename to base/www/htdocs/_ajax_vhost.php diff --git a/www/htdocs/assets/css/custom.css b/base/www/htdocs/assets/css/custom.css similarity index 99% rename from www/htdocs/assets/css/custom.css rename to base/www/htdocs/assets/css/custom.css index 8a9d694c..8f25462b 100644 --- a/www/htdocs/assets/css/custom.css +++ b/base/www/htdocs/assets/css/custom.css @@ -12,7 +12,7 @@ html, body { -webkit-tap-highlight-color: rgba(0,0,0,0); font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; - font-size: 14px; + font-size: 13px; line-height: 1.42857143; color: #333; background-color: #fff; diff --git a/www/htdocs/databases.php b/base/www/htdocs/databases.php similarity index 95% rename from www/htdocs/databases.php rename to base/www/htdocs/databases.php index e8735da3..cc81a9b4 100644 --- a/www/htdocs/databases.php +++ b/base/www/htdocs/databases.php @@ -31,7 +31,10 @@
  • Home
  • Virtual Hosts
  • Databases
  • -
  • PHP
  • +
  • |
  • +
  • PHP info
  • +
  • PHP opcache
  • +
  • MySQL info
  • diff --git a/www/htdocs/index.php b/base/www/htdocs/index.php similarity index 74% rename from www/htdocs/index.php rename to base/www/htdocs/index.php index 9f853de7..4cd831c5 100644 --- a/www/htdocs/index.php +++ b/base/www/htdocs/index.php @@ -31,7 +31,10 @@
  • Home
  • Virtual Hosts
  • Databases
  • -
  • PHP
  • +
  • |
  • +
  • PHP info
  • +
  • PHP opcache
  • +
  • MySQL info
  • @@ -58,15 +61,15 @@ Webserver -    (IP: ) + PHP -    (IP: ) + MySQL Server -    (IP: ) + @@ -104,29 +107,46 @@

    [docker] HTTPD

    - -- + IP Adress + +

    [docker] PHP

    + IP Adress + + MySQL Remote Port forwarded to PHP Docker? MySQL Remote Socket mounted on PHP Docker? - + PHP-MySQL connection test: localhost - + PHP-MySQL connection test: 127.0.0.1 - + PHP-MySQL connection test: - + PHP custom run-time options @@ -170,7 +190,7 @@ track_errors = - + @@ -180,30 +200,22 @@ track_errors =

    [docker] MySQL

    + IP Adress + + MySQL root password MySQL socket - + - MySQL custom run-time options - -
    -general_log             = 
    -innodb_buffer_pool_size = 
    -join_buffer_size        = 
    -sort_buffer_size        = 
    -read_rnd_buffer_size    = 
    -symbolic_links          = 
    -sql_mode                = 
    -									
    - + MySQL logging + - diff --git a/base/www/htdocs/mysqlinfo.php b/base/www/htdocs/mysqlinfo.php new file mode 100644 index 00000000..d171306c --- /dev/null +++ b/base/www/htdocs/mysqlinfo.php @@ -0,0 +1,90 @@ + + + + + + + + + + + + + DevilBox + + + + + + +
    + +

    MySQL Info

    +
    +
    + +
    + +
    + +
    + + + + + diff --git a/base/www/htdocs/opcache.php b/base/www/htdocs/opcache.php new file mode 100644 index 00000000..cf11cd0f --- /dev/null +++ b/base/www/htdocs/opcache.php @@ -0,0 +1,802 @@ + true, // show/hide the files tab + 'allow_invalidate' => true, // give a link to invalidate files + 'allow_reset' => true, // give option to reset the whole cache + 'allow_realtime' => true, // give option to enable/disable real-time updates + 'refresh_time' => 5, // how often the data will refresh, in seconds + 'size_precision' => 2, // Digits after decimal point + 'size_space' => false, // have '1MB' or '1 MB' when showing sizes + 'charts' => true, // show gauge chart or just big numbers + 'debounce_rate' => 250 // milliseconds after key press to send keyup event when filtering +]; + +/* + * Shouldn't need to alter anything else below here + */ + +if (!extension_loaded('Zend OPcache')) { + die('The Zend OPcache extension does not appear to be installed'); +} + +class OpCacheService +{ + protected $data; + protected $options; + protected $defaults = [ + 'allow_filelist' => true, + 'allow_invalidate' => true, + 'allow_reset' => true, + 'allow_realtime' => true, + 'refresh_time' => 5, + 'size_precision' => 2, + 'size_space' => false, + 'charts' => true, + 'debounce_rate' => 250 + ]; + + private function __construct($options = []) + { + $this->options = array_merge($this->defaults, $options); + $this->data = $this->compileState(); + } + + public static function init($options = []) + { + $self = new self($options); + if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) + && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' + ) { + if (isset($_GET['reset']) && $self->getOption('allow_reset')) { + echo '{ "success": "' . ($self->resetCache() ? 'yes' : 'no') . '" }'; + } else if (isset($_GET['invalidate']) && $self->getOption('allow_invalidate')) { + echo '{ "success": "' . ($self->resetCache($_GET['invalidate']) ? 'yes' : 'no') . '" }'; + } else { + echo json_encode($self->getData((empty($_GET['section']) ? null : $_GET['section']))); + } + exit; + } else if (isset($_GET['reset']) && $self->getOption('allow_reset')) { + $self->resetCache(); + header('Location: ?'); + exit; + } else if (isset($_GET['invalidate']) && $self->getOption('allow_invalidate')) { + $self->resetCache($_GET['invalidate']); + header('Location: ?'); + exit; + } + return $self; + } + + public function getOption($name = null) + { + if ($name === null) { + return $this->options; + } + return (isset($this->options[$name]) + ? $this->options[$name] + : null + ); + } + + public function getData($section = null, $property = null) + { + if ($section === null) { + return $this->data; + } + $section = strtolower($section); + if (isset($this->data[$section])) { + if ($property === null || !isset($this->data[$section][$property])) { + return $this->data[$section]; + } + return $this->data[$section][$property]; + } + return null; + } + + public function canInvalidate() + { + return ($this->getOption('allow_invalidate') && function_exists('opcache_invalidate')); + } + + public function resetCache($file = null) + { + $success = false; + if ($file === null) { + $success = opcache_reset(); + } else if (function_exists('opcache_invalidate')) { + $success = opcache_invalidate(urldecode($file), true); + } + if ($success) { + $this->compileState(); + } + return $success; + } + + protected function size($size) + { + $i = 0; + $val = array('b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + while (($size / 1024) > 1) { + $size /= 1024; + ++$i; + } + return sprintf('%.'.$this->getOption('size_precision').'f%s%s', + $size, ($this->getOption('size_space') ? ' ' : ''), $val[$i] + ); + } + + protected function compileState() + { + $status = opcache_get_status(); + $config = opcache_get_configuration(); + + $files = []; + if (!empty($status['scripts']) && $this->getOption('allow_filelist')) { + uasort($status['scripts'], function($a, $b) { + return $a['hits'] < $b['hits']; + }); + foreach ($status['scripts'] as &$file) { + $file['full_path'] = str_replace('\\', '/', $file['full_path']); + $file['readable'] = [ + 'hits' => number_format($file['hits']), + 'memory_consumption' => $this->size($file['memory_consumption']) + ]; + } + $files = array_values($status['scripts']); + } + + $overview = array_merge( + $status['memory_usage'], $status['opcache_statistics'], [ + 'used_memory_percentage' => round(100 * ( + ($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory']) + / $config['directives']['opcache.memory_consumption'])), + 'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']), + 'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2), + 'readable' => [ + 'total_memory' => $this->size($config['directives']['opcache.memory_consumption']), + 'used_memory' => $this->size($status['memory_usage']['used_memory']), + 'free_memory' => $this->size($status['memory_usage']['free_memory']), + 'wasted_memory' => $this->size($status['memory_usage']['wasted_memory']), + 'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']), + 'hits' => number_format($status['opcache_statistics']['hits']), + 'misses' => number_format($status['opcache_statistics']['misses']), + 'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']), + 'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']), + 'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']), + 'start_time' => date('Y-m-d H:i:s', $status['opcache_statistics']['start_time']), + 'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0 + ? 'never' + : date('Y-m-d H:i:s', $status['opcache_statistics']['last_restart_time']) + ) + ] + ] + ); + + $directives = []; + ksort($config['directives']); + foreach ($config['directives'] as $k => $v) { + $directives[] = ['k' => $k, 'v' => $v]; + } + + $version = array_merge( + $config['version'], + [ + 'php' => phpversion(), + 'server' => $_SERVER['SERVER_SOFTWARE'], + 'host' => (function_exists('gethostname') + ? gethostname() + : (php_uname('n') + ?: (empty($_SERVER['SERVER_NAME']) + ? $_SERVER['HOST_NAME'] + : $_SERVER['SERVER_NAME'] + ) + ) + ) + ] + ); + + return [ + 'version' => $version, + 'overview' => $overview, + 'files' => $files, + 'directives' => $directives, + 'blacklist' => $config['blacklist'], + 'functions' => get_extension_funcs('Zend OPcache') + ]; + } +} + +$opcache = OpCacheService::init($options); + +?> + + + + + + + + + + + + + DevilBox + + + + + OPcache statistics on <?php echo $opcache->getData('version', 'host'); ?> + + + + + + + + + + + + +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + getData('functions') as $func): ?> + + + +
    Available functions
    +
    +
    +
    +
    +
    +
    + getOption('allow_filelist')): ?> +

    + +
    +
    +
    + + + + + + + diff --git a/www/htdocs/php.php b/base/www/htdocs/phpinfo.php similarity index 89% rename from www/htdocs/php.php rename to base/www/htdocs/phpinfo.php index 69836673..a59f89a8 100644 --- a/www/htdocs/php.php +++ b/base/www/htdocs/phpinfo.php @@ -31,7 +31,10 @@
  • Home
  • Virtual Hosts
  • Databases
  • -
  • PHP
  • +
  • |
  • +
  • PHP info
  • +
  • PHP opcache
  • +
  • MySQL info
  • diff --git a/www/htdocs/vhosts.php b/base/www/htdocs/vhosts.php similarity index 95% rename from www/htdocs/vhosts.php rename to base/www/htdocs/vhosts.php index f8a1a947..56b2fab5 100644 --- a/www/htdocs/vhosts.php +++ b/base/www/htdocs/vhosts.php @@ -31,7 +31,10 @@
  • Home
  • Virtual Hosts
  • Databases
  • -
  • PHP
  • +
  • |
  • +
  • PHP info
  • +
  • PHP opcache
  • +
  • MySQL info
  • diff --git a/www/include/footer.php b/base/www/include/footer.php similarity index 100% rename from www/include/footer.php rename to base/www/include/footer.php diff --git a/www/include/functions.php b/base/www/include/functions.php similarity index 83% rename from www/include/functions.php rename to base/www/include/functions.php index e43c70f5..5e6eea2e 100644 --- a/www/include/functions.php +++ b/base/www/include/functions.php @@ -1,6 +1,5 @@ getMessage().': '.mysqli_connect_error(); + + if (!($link = @mysqli_connect($host, $user, $pass))) { + $err = 'Failed to connect: ' .mysqli_connect_error(); return FALSE; } + mysqli_close($link); + return TRUE; +} -// if (!($link = @mysqli_connect($host, $user, $pass))) { -// $err = mysqli_connect_error(); -// return FALSE; -// } + + + +/** + * Connect to database + * + * @param [type] $err [description] + * @param [type] $host [description] + * @param [type] $pass [description] + * @param [type] $user [description] + * @return [type] [description] + */ +function my_mysql_connect(&$err, $pass = NULL, $user = NULL) +{ + + if ($pass === NULL) { + $pass = $GLOBALS['MYSQL_ROOT_PASS']; + } + if ($user === NULL) { + $user = 'root'; + } + + + if (!($link = @mysqli_connect('localhost', $user, $pass))) { + $err = 'Failed to connect: ' .mysqli_connect_error(); + if (!($link = @mysqli_connect('127.0.0.1', $user, $pass))) { + $err = 'Failed to connect: ' .mysqli_connect_error(); + if (!($link = @mysqli_connect($GLOBALS['MYSQL_HOST_ADDR'], $user, $pass))) { + $err = 'Failed to connect: ' .mysqli_connect_error(); + return FALSE; + } + } + } + $err = FALSE; return $link; } + + + /** * Close Database connection * @@ -58,7 +94,10 @@ function my_mysql_connect(&$err, $host = NULL, $pass = NULL, $user = NULL) * @return [type] [description] */ function my_mysqli_close($link) { - return mysqli_close($link); + if (is_object($link)) { + return mysqli_close($link); + } + return FALSE; } @@ -85,7 +124,9 @@ function my_mysqli_select(&$err, $link, $query, $callback = NULL) $callback($row, $data); } } else { - $data[] = $row; + while ($row = $result->fetch_array(MYSQLI_ASSOC)) { + $data[] = $row; + } } mysqli_free_result($result); @@ -181,7 +222,7 @@ function getTableCount($db_name) { * @param [type] $key [description] * @return [type] [description] */ -function getMySQLConfig($key) { +function getMySQLConfigByKey($key) { $key = str_replace('-', '_', $key); $callback = function ($row, &$data) use ($key) { @@ -200,6 +241,17 @@ function getMySQLConfig($key) { } } +function getMySQLConfig() { + $callback = function ($row, &$data) { + $key = $row['Variable_name']; + $val = $row['Value']; + $data[$key] = $val; + }; + + $sql = 'SHOW VARIABLES;'; + return my_mysqli_select($error, $GLOBALS['MY_MYSQL_LINK'], $sql, $callback); + +} @@ -351,7 +403,7 @@ function getHttpVersion() { */ function getMySQLVersion() { - return getMySQLConfig('version_comment') . ' ' . getMySQLConfig('version'); + return getMySQLConfigByKey('version_comment') . ' ' . getMySQLConfigByKey('version'); } function getPHPVersion() { diff --git a/cfg/README.md b/cfg/README.md new file mode 100644 index 00000000..ccae6386 --- /dev/null +++ b/cfg/README.md @@ -0,0 +1,3 @@ +# Devilbox user-defined settings + +Use this folders to add your custom configuration. diff --git a/cfg/mysql-5.5/README.md b/cfg/mysql-5.5/README.md new file mode 100644 index 00000000..db8213f1 --- /dev/null +++ b/cfg/mysql-5.5/README.md @@ -0,0 +1,5 @@ +# User-defined MySQL configuration + +Add as many `*.cnf` files here as you wish. + +Files not ending with `*.cnf` will not be picked up during startup. diff --git a/cfg/mysql-5.5/devilbox-user.cnf-example b/cfg/mysql-5.5/devilbox-user.cnf-example new file mode 100644 index 00000000..8dc0d8ad --- /dev/null +++ b/cfg/mysql-5.5/devilbox-user.cnf-example @@ -0,0 +1,3 @@ +[mysqld] +slow_query_log = 1 +log_queries_not_using_indexes = 1 diff --git a/docker-compose.yml b/docker-compose.yml index 6b1f55d6..a6f608fb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -70,25 +70,24 @@ services: # ---- Format: ---- # HOST-DIRECTORY : DOCKER-DIRECTORY - # Custom scripts/binaries required for httpd server vhost # configuration to work. # (configured in /etc/${HTTPD_SERVER}/02-vhost-mass.conf) - - ./bin/${HTTPD_SERVER}:/opt/bin + - ./base/bin/${HTTPD_SERVER}:/opt/bin # Mount user-defined httpd configuration files # @see environment::CUSTOM_HTTPD_CONF_DIR for how this # is added in httpd server - - ./etc/${HTTPD_SERVER}:/etc/${HTTPD_SERVER} + - ./base/etc/${HTTPD_SERVER}:/etc/${HTTPD_SERVER} + + # Mount custom intranet + # (configured in /etc/${HTTPD_SERVER}/01-vhost-default.conf) + - ./base/www:/var/www/default # Mount user-defined httpd log # @see ./etc/${HTTPD_SERVER}/*.conf for log defines - ./log/${HTTPD_SERVER}:/var/log/${HTTPD_SERVER} - # Mount custom intranet - # (configured in /etc/${HTTPD_SERVER}/01-vhost-default.conf) - - ./www:/var/www/default - # Mount custom mass virtual hosting # (configured in /etc/${HTTPD_SERVER}/02-vhost-mass.conf) - ${HOST_PATH_TO_WWW_DOCROOTS}:/shared/httpd @@ -180,16 +179,16 @@ services: # ---- Format: ---- # HOST-DIRECTORY : DOCKER-DIRECTORY + # Mount custom intranet + # (configured in /etc/${HTTPD_SERVER}/01-vhost-default.conf) + - ./base/www:/var/www/default + # Mount logs - ./log/${PHP_SERVER}:/var/log/php-fpm # Mount MySQL Socket directory - ./run/mysql:/tmp/mysql - # Mount custom intranet - # (configured in /etc/${HTTPD_SERVER}/01-vhost-default.conf) - - ./www:/var/www/default - # Mount custom mass virtual hosting # (configured in /etc/${HTTPD_SERVER}/02-vhost-mass.conf) - ${HOST_PATH_TO_WWW_DOCROOTS}:/shared/httpd @@ -222,17 +221,6 @@ services: # Runtime settings - MYSQL_GENERAL_LOG=${MYSQL_GENERAL_LOG} - - MYSQL_INNODB_LOG_FILE_SIZE=${MYSQL_INNODB_LOG_FILE_SIZE} - - MYSQL_INNODB_BUFFER_POOL_SIZE=${MYSQL_INNODB_BUFFER_POOL_SIZE} - - MYSQL_JOIN_BUFFER_SIZE=${MYSQL_JOIN_BUFFER_SIZE} - - MYSQL_SORT_BUFFER_SIZE=${MYSQL_SORT_BUFFER_SIZE} - - MYSQL_READ_RND_BUFFER_SIZE=${MYSQL_READ_RND_BUFFER_SIZE} - - MYSQL_SYMBOLIC_LINKS=${MYSQL_SYMBOLIC_LINKS} - - MYSQL_SQL_MODE=${MYSQL_SQL_MODE} - - # Used for repairing - - MYSQL_INNODB_FORCE_RECOVERY=${MYSQL_INNODB_FORCE_RECOVERY} - - MYSQL_MODE=${MYSQL_MODE} ports: # [local-machine:]local-port:docker-port @@ -252,6 +240,10 @@ services: # Mount MySQL Socket directory - ./run/mysql:/tmp/mysql + # Mount devilbox user-defined cnf files in order + # to overwrite the MySQL server configuration + - ./cfg/${MYSQL_SERVER}:/etc/mysql/conf.d + # Mount MySQL Data directory - ${HOST_PATH_TO_MYSQL_DATADIR}:/var/lib/mysql