diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d2b04a3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +.idea + +.gitattributes +.gitignore +.git + +.dockerignore +Dockerfile +docker-compose.yml + +LICENSE.md +README.md + +storage.json + +/vendor +nbproject/ + +.vagrant +vagrant +Vagrantfile diff --git a/.gitignore b/.gitignore index 3aeb516..5216986 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea /vendor .vagrant -nbproject/ \ No newline at end of file +nbproject/ +config.local.php diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..618a7b2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM php:8.4-apache +LABEL maintainer="Rion Dooley " + +ENV APACHE_DOCROOT="/var/www" + +# Add custom default apache virtual host with combined error and access logging to stdout +COPY docker/apache_vhost /etc/apache2/sites-available/000-default.conf +COPY docker/php.ini /usr/local/etc/php + +# Add custom entrypoint to inject runtime environment variables into beanstalk console config +COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint +RUN chmod +x /usr/local/bin/docker-entrypoint +CMD ["/usr/local/bin/docker-entrypoint"] + +WORKDIR "${APACHE_DOCROOT}" +COPY . ./ diff --git a/README.md b/README.md index 889ad97..40fd336 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,25 @@ **Features** -- Common list of servers in config for all users +- Common list of servers in config for all users + optional Basic Auth +- Global server list can be set via BEANSTALK_SERVERS environment variable - Each user can add its own personal Beanstalkd server -- Full list of available tubes - Complete statistics about jobs in tubes - Realtime auto-update with highlighting of changed values -- You can view jobs in ready/delayed/buried states in every tube -- You can add/kick/delete jobs in every tube -- You can select multiple tubes by regExp and clear them -- You can move jobs between tubes -- Ability to Pause tubes -- Saved jobs (store sample jobs as a template, kick/edit them, very useful for development) -- Customizable UI (code highlighter, choose columns, edit auto refresh seconds, pause tube seconds) +- View jobs in ready/delayed/buried states in every tube +- Highlighting of buried jobs for better visibility +- Add/kick/delete jobs in every tube +- Select multiple tubes by regular expression and clear them +- Saved jobs: Store sample jobs as templates, kick/edit them (useful for development) +- Search within job data fields +- Move jobs between tubes +- Pause tubes +- Configurable UI settings (auto-refresh, decoding, pause duration, etc.) + +**Change log** + +Navigate to [Releases](https://github.com/ptrofimov/beanstalk_console/releases). -Change log on [Releases](https://github.com/ptrofimov/beanstalk_console/releases). **Installation** @@ -37,50 +42,42 @@ Then, use the `create-project` command to generate a new application: Composer will install the Beanstalk Console and all its dependencies under the `path/to/install` directory. -### Setup using vagrant - -Install [VirtualBox](https://www.virtualbox.org/wiki/Downloads) and [vagrant](http://www.vagrantup.com/downloads.html) then run (from project root): - - vagrant up - -After provision beanstalk console will be available at [http://localhost:7654](http://localhost:7654) (port could be configured in Vagrantfile) - -### Download an Archive File +### Run as a Docker container -[Download](https://github.com/ptrofimov/beanstalk_console/archive/master.zip), unzip files to your *wwww* directory and launch from *public* directory, enjoy! +Install [Docker](https://docs.docker.com/installation/) then build and run with the following command (from project root): + docker build --rm -t beanstalk_console . + docker run -d -p "80:80" --name beanstalk_console beanstalk_console -**Authors:** Petr Trofimov, Sergey Lysenko, Pentium10 +If you would rather just run the existing automated build of this project, run (from project root): --------------------------------------------------- + docker run -d -p "80:80" -e APACHE_PORT=80 --name beanstalk_console agaveapi/beanstalkd-console -# Beanstalk консоль ![Русская версия](http://upload.wikimedia.org/wikipedia/en/thumb/f/f3/Flag_of_Russia.svg/22px-Flag_of_Russia.svg.png) +To configure webapp with a custom beanstalk server to load at runtime, set the `BEANSTALKD_HOST` and `BEANSTALKD_PORT` environment variables. -*Административная консоль для сервера очередей [Beanstalk](http://kr.github.com/beanstalkd), написанная на PHP* + docker run -d -p 80:80 \ + --name beanstalk_console \ + -e 'BEANSTALKD_HOST=beanstalkd' \ + -e 'BEANSTALKD_PORT=11300' \ + beanstalk_console -**Возможности** +To spin up a console with a beanstalkd server all at once, install [Docker Compose](https://docs.docker.com/compose/) and run (from project root): -- Общий список серверов в конфиге для всех пользователей -- Каждый пользователь может добавить свой персональный сервер -- Полный список доступных труб -- Полная статистика тасков в трубах -- Realtime-обновление с подсветкой изменившихся значений -- Вы можете просматривать таски в каждой трубе (ready/delayed/buried) -- Вы можете выполнять операции с тасками в каждой трубе (add/kick/delete) + docker-compose up -**Установка** +### Setup using vagrant -[Скачайте](https://github.com/ptrofimov/beanstalk_console/archive/master.zip), положите распакованные файлы в www папку и наслаждайтесь! +Install [VirtualBox](https://www.virtualbox.org/wiki/Downloads) and [vagrant](http://www.vagrantup.com/downloads.html) then run (from project root): -**Установка с помощью vagrant** + vagrant up -Установите [VirtualBox](https://www.virtualbox.org/wiki/Downloads) и [vagrant](http://www.vagrantup.com/downloads.html) затем запустите (в корневой директории проекта): +After provision beanstalk console will be available at [http://localhost:7654](http://localhost:7654) (port could be configured in Vagrantfile) - vagrant up +### Download an Archive File -После завершения провизии консоль будет доступна по адресу [http://localhost:7654](http://localhost:7654) (порт можно сконфигурировать в Vagrantfile) +[Download](https://github.com/ptrofimov/beanstalk_console/archive/master.zip), unzip files to your *www* directory and launch from *public* directory, enjoy! -**Авторы:** Петр Трофимов, Сергей Лысенко, Pentium10 +**Authors:** Petr Trofimov, Sergey Lysenko, Pentium10 -------------------------------------------------- diff --git a/Vagrantfile b/Vagrantfile index 1e3c0ab..616e87e 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -4,8 +4,8 @@ VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - config.vm.box = "precise64" - config.vm.box_url = "http://files.vagrantup.com/precise64.box" + config.vm.box = "hashicorp/precise64" + config.vm.box_url = "https://vagrantcloud.com/hashicorp/boxes/precise64/versions/1.1.0/providers/virtualbox.box" # expose ports config.vm.network :forwarded_port, host: 7654, guest: 80 diff --git a/composer.json b/composer.json index 5ddc95c..7395e7f 100644 --- a/composer.json +++ b/composer.json @@ -3,14 +3,14 @@ "description": "Admin console for Beanstalk queue server", "keywords": ["beanstalk", "beanstalkd", "queue", "console", "gui", "admin", "web admin", "monitoring", "stats", "interface", "php"], "type": "project", - "authors": [ + "authors": [ { "name": "Petr Trofimov" }, { "name": "Sergey Lysenko" }, - { + { "name": "Pentium10" } ], @@ -20,6 +20,7 @@ "license": "MIT", "require": { "php": ">=5.2.0", - "ext-json": "*" + "ext-json": "*", + "ext-mbstring": "*" } } diff --git a/config.php b/config.php index f509117..c0ec5db 100644 --- a/config.php +++ b/config.php @@ -1,16 +1,78 @@ - array(/* 'localhost:11300' */), - /** - * Saved samples jobs are kept in this file, must be writable - */ - 'storage' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'storage.json', - /** - * Version number - */ - 'version' => '1.5.1', -); + array(/* 'Local Beanstalkd' => 'beanstalk://localhost:11300', ... */), + /** + * Saved samples jobs are kept in this file, must be writable + */ + 'storage' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'storage.json', + /** + * Optional Basic Authentication + */ + 'auth' => array( + 'enabled' => false, + 'username' => 'admin', + 'password' => 'password', + ), + + /** + * Default UI settings (used when no cookie is present). + * These values will be overridden by user-specific selection in Settings screen and kept in cookies. + * Keys use a positive 'enableFeature' convention where applicable. + * 'true' means the feature is ON by default. + * 'false' means the feature is OFF by default. + */ + 'settings' => array( + // Numeric settings + 'tubePauseSeconds' => -1, // Default: -1 (uses beanstalkd default of 1 hour) + 'autoRefreshTimeoutMs' => 500, // Default: 500ms interval for auto-refresh + 'searchResultLimit' => 25, // Default: 25 results in search + + // Boolean settings (true = enabled/checked by default) + 'enableJsonDecode' => true, // Default: Job data IS json_decoded by default + 'enableJobDataHighlight' => true, // Default: Job data highlighting IS enabled by default + 'enableAutoRefreshLoad' => false, // Default: Auto-refresh IS disabled on page load + 'enableUnserialization' => false, // Default: Job data IS NOT unserialized by default + 'enableBase64Decode' => false, // Default: Job data IS NOT base64_decoded by default + ), +); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5ff9c51 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +## +# docker-compose.yml +# +# author: Rion Dooley +# +# This is a basic Docker Compose file to start the beanstalkd console webapp and a +# fully functional beanstalkd instance in a single command. The beanstalkd server +# is accessible on standard port 11300. The beanstalkd console is available at +# http://:9080. +# +# By default, a new image will be built from the the source code in this repository. +# You may also skip the build step and use the public, automated build of this +# repository by commenting out the build argument and uncommenting the image argument. +# +# If you need a persistent beanstalkd binlog, simply uncomment the last 5 lines. +# +# + +--- +version: '3' + + +services: + web: + ## Optionally; you can use a ready image changing: + ## * `build: .` + ## into: + ## * image: agaveapi/beanstalkd-console + build: . + ports: + - 80:80 + environment: + - BEANSTALKD_HOST=beanstalkd + links: + - beanstalkd + beanstalkd: + image: dinamic/docker-alpine-beanstalkd + volumes: + - beanstalkd_data:/var/lib/beanstald + +volumes: + beanstalkd_data: diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..dccdb9c --- /dev/null +++ b/docker/README.md @@ -0,0 +1,50 @@ +# Running Beanstalkd Console +================================ + +This project has been Dockerized for easier deployment and use. Instructions on building and running are given here. + +## Building + +To build a fresh container, run the following command, substituting whatever tag you would like to give the resulting image. + +``` +docker build -rm -t beanstalkd-console . +``` + +## Running Containers + +Once built, you can run a container manually using the following command. + +``` +docker run -d -p 80:80 --name beanstalk_console beanstalk_console +``` + +If you need a beanstalk server to test against, you can use the public image created by the [Agave](http://agaveapi.co) dev team in the [Docker Registry](https://hub.docker.com/r/agaveapi/beanstalkd), `agaveapi/beanstalkd`. The following command will start a beanstalkd on the host machine and make the the default port available. + +``` +docker run -h beanstalkd -d -p 11300:11300 beanstalkd +``` + +## Runtime Configuration + +To configure webapp with a custom beanstalk server to load at runtime, set the `BEANSTALKD_HOST` and `BEANSTALKD_PORT` environment variables. + +``` +docker run -d -p 80:80 \ + --name beanstalk_console \ + -e 'BEANSTALKD_HOST=beanstalkd' \ + -e 'BEANSTALKD_PORT=11300' \ + beanstalk_console +``` + +## Logging + +By default, all access and error logs will stream to stdout and be available through the Docker Event Stream and `docker logs` command. + +## Orchestrating Infrastructure + +To make the orchestration process a bit easier, a [Docker Compose](https://docs.docker.com/compose/) file is available. The following command will start both the console and daemon servers ready to use out of the box. The beanstalk server will be available on the default `11300` port. The beanstalkd console will be available at `http:///`. + +``` +docker-compose up +``` diff --git a/docker/apache_vhost b/docker/apache_vhost new file mode 100644 index 0000000..c71936f --- /dev/null +++ b/docker/apache_vhost @@ -0,0 +1,7 @@ + + ServerSignature off + ServerAdmin webmaster@localhost + DocumentRoot /var/www/public + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100755 index 0000000..bd1c157 --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e + +# Change ownership for apache happiness +chown -R www-data:www-data "${APACHE_DOCROOT}" + +TARGET_LINE_PATTERN="^\s*'servers'\s*=>\s*array.*" + +if [[ -n "$BEANSTALKD_HOST" ]]; then + if [[ -z "$BEANSTALKD_PORT" ]]; then + BEANSTALKD_PORT=11300 + fi + REPLACEMENT_STRING=" 'servers' => array('$BEANSTALKD_HOST' => 'beanstalk://$BEANSTALKD_HOST:$BEANSTALKD_PORT')," + sed -i "s#${TARGET_LINE_PATTERN}#${REPLACEMENT_STRING}#g" /var/www/config.php + +elif [[ -n "$BEANSTALKD_PORT_11300_TCP_ADDR" ]]; then + BEANSTALKD_HOST=$BEANSTALKD_PORT_11300_TCP_ADDR + if [[ -z "$BEANSTALKD_PORT" ]]; then + if [[ -n "$BEANSTALKD_PORT_11300_TCP_PORT" ]]; then + BEANSTALKD_PORT=$BEANSTALKD_PORT_11300_TCP_PORT + else # Default if specific port not found via link + BEANSTALKD_PORT=11300 + fi + fi + if [[ -z "$BEANSTALKD_PORT" ]]; then # If BEANSTALKD_PORT (global) was not set + if [[ -n "$BEANSTALKD_PORT_11300_TCP_PORT" ]]; then + BEANSTALKD_PORT=$BEANSTALKD_PORT_11300_TCP_PORT + else + BEANSTALKD_PORT=11300 # Fallback if linked port is also not set + fi + fi + + REPLACEMENT_STRING=" 'servers' => array('$BEANSTALKD_HOST' => 'beanstalk://$BEANSTALKD_HOST:$BEANSTALKD_PORT')," + sed -i "s#${TARGET_LINE_PATTERN}#${REPLACEMENT_STRING}#g" /var/www/config.php +fi + +rm -f /var/run/apache2/apache2.pid + +source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND \ No newline at end of file diff --git a/docker/php.ini b/docker/php.ini new file mode 100644 index 0000000..6be5fb3 --- /dev/null +++ b/docker/php.ini @@ -0,0 +1,1925 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it's +; much more verbose when it comes to errors. We recommending using the +; development version only in development environments as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is php.ini-production INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.bug_compat_42 +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.bug_compat_warn +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.hash_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; url_rewriter.tags +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It's been +; recommended for several years that you not use the short tag "short cut" and +; instead to use the full tag combination. With the wide spread use +; of XML and use of these tags by other languages, the server can become easily +; confused and end up parsing the wrong code in the wrong context. But because +; this short cut has been a feature for such a long time, it's currently still +; supported for backwards compatibility, but we recommend you don't use them. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/short-open-tag +short_open_tag = Off + +; Allow ASP-style <% %> tags. +; http://php.net/asp-tags +asp_tags = Off + +; The number of significant digits displayed in floating point numbers. +; http://php.net/precision +precision = 14 + +; Output buffering is a mechanism for controlling how much output data +; (excluding headers and cookies) PHP should keep internally before pushing that +; data to the client. If your application's output exceeds this setting, PHP +; will send that data in chunks of roughly the size you specify. +; Turning on this setting and managing its maximum buffer size can yield some +; interesting side-effects depending on your application and web server. +; You may be able to send headers and cookies after you've already sent output +; through print or echo. You also may see performance benefits if your server is +; emitting less packets due to buffered output versus PHP streaming the output +; as it gets it. On production servers, 4096 bytes is a good setting for performance +; reasons. +; Note: Output buffering can also be controlled via Output Buffering Control +; functions. +; Possible Values: +; On = Enabled and buffer is unlimited. (Use with caution) +; Off = Disabled +; Integer = Enables the buffer and sets its maximum size in bytes. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 +; http://php.net/output-buffering +output_buffering = 4096 + +; You can redirect all of the output of your scripts to a function. For +; example, if you set output_handler to "mb_output_handler", character +; encoding will be transparently converted to the specified encoding. +; Setting any output handler automatically turns on output buffering. +; Note: People who wrote portable scripts should not depend on this ini +; directive. Instead, explicitly set the output handler using ob_start(). +; Using this ini directive may cause problems unless you know what script +; is doing. +; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler" +; and you cannot use both "ob_gzhandler" and "zlib.output_compression". +; Note: output_handler must be empty if this is set 'On' !!!! +; Instead you must use zlib.output_handler. +; http://php.net/output-handler +;output_handler = + +; Transparent output compression using the zlib library +; Valid values for this option are 'off', 'on', or a specific buffer size +; to be used for compression (default is 4KB) +; Note: Resulting chunk size may vary due to nature of compression. PHP +; outputs chunks that are few hundreds bytes each as a result of +; compression. If you prefer a larger chunk size for better +; performance, enable output_buffering in addition. +; Note: You need to use zlib.output_handler instead of the standard +; output_handler, or otherwise the output will be corrupted. +; http://php.net/zlib.output-compression +zlib.output_compression = Off + +; http://php.net/zlib.output-compression-level +;zlib.output_compression_level = -1 + +; You cannot specify additional output handlers if zlib.output_compression +; is activated here. This setting does the same as output_handler but in +; a different order. +; http://php.net/zlib.output-handler +;zlib.output_handler = + +; Implicit flush tells PHP to tell the output layer to flush itself +; automatically after every output block. This is equivalent to calling the +; PHP function flush() after each and every call to print() or echo() and each +; and every HTML block. Turning this option on has serious performance +; implications and is generally recommended for debugging purposes only. +; http://php.net/implicit-flush +; Note: This directive is hardcoded to On for the CLI SAPI +implicit_flush = Off + +; The unserialize callback function will be called (with the undefined class' +; name as parameter), if the unserializer finds an undefined class +; which should be instantiated. A warning appears if the specified function is +; not defined, or if the function doesn't include/implement the missing class. +; So only set this entry, if you really want to implement such a +; callback-function. +unserialize_callback_func = + +; When floats & doubles are serialized store serialize_precision significant +; digits after the floating point. The default value ensures that when floats +; are decoded with unserialize, the data will remain the same. +serialize_precision = 17 + +; open_basedir, if set, limits all file operations to the defined directory +; and below. This directive makes most sense if used in a per-directory +; or per-virtualhost web server configuration file. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/open-basedir +;open_basedir = + +; This directive allows you to disable certain functions for security reasons. +; It receives a comma-delimited list of function names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-functions +disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, + +; This directive allows you to disable certain classes for security reasons. +; It receives a comma-delimited list of class names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-classes +disable_classes = + +; Colors for Syntax Highlighting mode. Anything that's acceptable in +; would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +;realpath_cache_size = 16k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 300 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +; max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 1G + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it's automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; It's recommended that errors be logged on production servers rather than +; having the errors sent to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. But, it's strongly recommended that you +; leave this setting off on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/track-errors +track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on NT, not valid in Windows 95). +;error_log = syslog + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P,C,E & S) should +; be registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive are +; specified in the same manner as the variables_order directive, EXCEPT one. +; Leaving this value empty will cause PHP to use the value set in the +; variables_order directive. It does not mean it will leave the super globals +; array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 32M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a character encoding using +; the Content-type: header. To disable sending of the charset, simply +; set it to be empty. +; +; PHP's built-in default is text/html +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to empty. +; http://php.net/default-charset +;default_charset = "UTF-8" + +; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is +; to disable this feature. If post reading is disabled through +; enable_post_data_reading, $HTTP_RAW_POST_DATA is *NOT* populated. +; http://php.net/always-populate-raw-post-data +;always_populate_raw_post_data = On + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/usr/share/php" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +; sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If it's set 0 PHP sends Status: header that +; is supported by Apache. When this option is set to 1 PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 32M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename.extension +; +; For example, on Windows: +; +; extension=msql.dll +; +; ... or under UNIX: +; +; extension=msql.so +; +; ... or with a path: +; +; extension=/path/to/extension/msql.so +; +; If you only provide the name of the extension, PHP will look for it in its +; default extension directory. +; +extension=zip.so + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +date.timezone ='America/Chicago' + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +;iconv.input_encoding = ISO-8859-1 +;iconv.internal_encoding = ISO-8859-1 +;iconv.output_encoding = ISO-8859-1 + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING + +[sqlite] +; http://php.net/sqlite.assoc-case +;sqlite.assoc_case = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(), even in safe mode. +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on NT, not valid in Windows 95). +;mail.log = syslog + +[SQL] +; http://php.net/sql.safe-mode +sql.safe_mode = Off + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQL] +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysql.allow_local_infile +mysql.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysql.allow-persistent +mysql.allow_persistent = On + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysql.cache_size +mysql.cache_size = 2000 + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysql.max-persistent +mysql.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/mysql.max-links +mysql.max_links = -1 + +; Default port number for mysql_connect(). If unset, mysql_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysql.default-port +mysql.default_port = + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysql.default-socket +mysql.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-host +mysql.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-user +mysql.default_user = + +; Default password for mysql_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysql.default-password +mysql.default_password = + +; Maximum time (in seconds) for connect timeout. -1 means no limit +; http://php.net/mysql.connect-timeout +mysql.connect_timeout = 60 + +; Trace mode. When trace_mode is active (=On), warnings for table/index scans and +; SQL-Errors will be displayed. +; http://php.net/mysql.trace-mode +mysql.trace_mode = Off + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[Sybase-CT] +; Allow or prevent persistent links. +; http://php.net/sybct.allow-persistent +sybct.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/sybct.max-persistent +sybct.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/sybct.max-links +sybct.max_links = -1 + +; Minimum server message severity to display. +; http://php.net/sybct.min-server-severity +sybct.min_server_severity = 10 + +; Minimum client message severity to display. +; http://php.net/sybct.min-client-severity +sybct.min_client_severity = 10 + +; Set per-context timeout +; http://php.net/sybct.timeout +;sybct.timeout= + +;sybct.packet_size + +; The maximum time in seconds to wait for a connection attempt to succeed before returning failure. +; Default: one minute +;sybct.login_timeout= + +; The name of the host you claim to be connecting from, for display by sp_who. +; Default: none +;sybct.hostname= + +; Allows you to define how often deadlocks are to be retried. -1 means "forever". +; Default: 0 +;sybct.deadlock_retry_count= + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if you +; or your OS have problems with lots of files in one directory, and is +; a more efficient layout for servers that handle lots of sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/var/lib/php5" + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the end all be all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 0 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; PHP 4.2 and less have an undocumented feature/bug that allows you to +; to initialize a session variable in the global scope. +; PHP 4.3 and later will warn you, if this feature is used. +; You can disable the feature and the warning separately. At this time, +; the warning is only displayed, if bug_compat_42 is enabled. This feature +; introduces some serious security problems if not handled correctly. It's +; recommended that you do not use this feature on production servers. But you +; should enable this on development servers and enable the warning as well. If you +; do not enable the feature on development servers, you won't be warned when it's +; used and debugging errors caused by this can be difficult to track down. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-42 +session.bug_compat_42 = Off + +; This setting controls whether or not you are warned by PHP when initializing a +; session value into the global space. session.bug_compat_42 must be enabled before +; these warnings can be issued by PHP. See the directive above for more information. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-warn +session.bug_compat_warn = Off + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; How many bytes to read from the file. +; http://php.net/session.entropy-length +;session.entropy_length = 32 + +; Specified here to create the session id. +; http://php.net/session.entropy-file +; Defaults to /dev/urandom +; On systems that don't have /dev/urandom but do have /dev/arandom, this will default to /dev/arandom +; If neither are found at compile time, the default is no entropy file. +; On windows, setting the entropy_length setting will activate the +; Windows random source (using the CryptoAPI) +;session.entropy_file = /dev/urandom + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Select a hash function for use in generating session ids. +; Possible Values +; 0 (MD5 128 bits) +; 1 (SHA-1 160 bits) +; This option may also be set to the name of any hash function supported by +; the hash extension. A list of available hashes is returned by the hash_algos() +; function. +; http://php.net/session.hash-function +session.hash_function = 0 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.hash_bits_per_character = 5 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; form/fieldset are special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; http://php.net/url-rewriter.tags +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +[MSSQL] +; Allow or prevent persistent links. +mssql.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +mssql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +mssql.max_links = -1 + +; Minimum error severity to display. +mssql.min_error_severity = 10 + +; Minimum message severity to display. +mssql.min_message_severity = 10 + +; Compatibility mode with old versions of PHP 3.0. +mssql.compatibility_mode = Off + +; Connect timeout +;mssql.connect_timeout = 5 + +; Query timeout +;mssql.timeout = 60 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textlimit = 4096 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textsize = 4096 + +; Limits the number of records in each batch. 0 = all records in one batch. +;mssql.batchsize = 0 + +; Specify how datetime and datetim4 columns are returned +; On => Returns data converted to SQL server settings +; Off => Returns values as YYYY-MM-DD hh:mm:ss +;mssql.datetimeconvert = On + +; Use NT authentication when connecting to the server +mssql.secure_connection = Off + +; Specify max number of processes. -1 = library default +; msdlib defaults to 25 +; FreeTDS defaults to 4096 +;mssql.max_procs = -1 + +; Specify client character set. +; If empty or not set the client charset from freetds.conf is used +; This is only used when compiled with FreeTDS +;mssql.charset = "ISO-8859-1" + +[Assertion] +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Issue a PHP warning for each failed assertion. +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; internal/script encoding. +; Some encoding cannot work as internal encoding. +; (e.g. SJIS, BIG5, ISO-2022-*) +; http://php.net/mbstring.internal-encoding +;mbstring.internal_encoding = UTF-8 + +; http input encoding. +; http://php.net/mbstring.http-input +;mbstring.http_input = UTF-8 + +; http output encoding. mb_output_handler must be +; registered as output buffer to function +; http://php.net/mbstring.http-output +;mbstring.http_output = pass + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; auto means +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[mcrypt] +; For more information about mcrypt settings see http://php.net/mcrypt-module-open + +; Directory where to load mcrypt algorithms +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.algorithms_dir= + +; Directory where to load mcrypt modes +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.modes_dir= + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +;opcache.enable=0 + +; Determines if Zend OPCache is enabled for the CLI version of PHP +;opcache.enable_cli=0 + +; The OPcache shared memory storage size. +;opcache.memory_consumption=64 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=4 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 100000 are allowed. +;opcache.max_accelerated_files=2000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +;opcache.validate_timestamps=1 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the + ;size of the optimized code. +;opcache.save_comments=1 + +; If disabled, PHPDoc comments are not loaded from SHM, so "Doc Comments" +; may be always stored (save_comments=1), but not loaded by applications +; that don't need them anyway. +;opcache.load_comments=1 + +; If enabled, a fast shutdown sequence is used for the accelerated code +;opcache.fast_shutdown=0 + +; Allow file existence override (file_exists, etc.) performance feature. +;opcache.enable_file_override=0 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0xffffffff + +;opcache.inherited_hack=1 +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +; Local Variables: +; tab-width: 4 +; End: +detect_unicode = Off diff --git a/lib/BeanstalkInterface.class.php b/lib/BeanstalkInterface.class.php index 22b6886..9588456 100644 --- a/lib/BeanstalkInterface.class.php +++ b/lib/BeanstalkInterface.class.php @@ -3,16 +3,34 @@ class BeanstalkInterface { protected $_contentType; + protected $_tubes; public $_client; + private $settings; - public function __construct($server) { - $list = explode(':', $server); - $this->_client = new Pheanstalk($list[0], isset($list[1]) ? $list[1] : ''); + /** + * Constructor + * + * @param string $server The server connection string (e.g., "localhost:11300" or "beanstalk://host:port"). + * @param Settings $settings The Settings object instance. + */ + public function __construct($server, $settings = null) { + if (strpos($server, "beanstalk://") === 0) { + $url = parse_url($server); + $host = $url['host']; + $port = $url['port']; + } else { + $list = explode(':', $server); + $host = $list[0]; + $port = isset($list[1]) ? $list[1] : ''; + } + $this->_client = new Pheanstalk($host, $port); + $this->settings = $settings ?? new Settings(); } public function getTubes() { $tubes = $this->_client->listTubes(); sort($tubes); + $this->_tubes = $tubes; return $tubes; } @@ -85,8 +103,8 @@ public function getServerStats() { public function getTubesStats() { $stats = array(); - foreach ($this->getTubes() as $tube) { - $stats[] = $this->getTubeStats($tube); + foreach ($this->_tubes ?? $this->getTubes() as $tube) { + $stats[$tube] = $this->getTubeStats($tube); } return $stats; } @@ -127,8 +145,8 @@ public function getTubeStats($tube) { continue; } - $stats[] = array( - 'key' => $nameTube[$key], + $stats[$key] = array( + 'key' => $key, 'value' => $value, 'descr' => isset($descr[$key]) ? $descr[$key] : ''); } @@ -174,7 +192,6 @@ public function deleteDelayed($tube) { } public function addJob($tubeName, $tubeData, $tubePriority = Pheanstalk::DEFAULT_PRIORITY, $tubeDelay = Pheanstalk::DEFAULT_DELAY, $tubeTtr = Pheanstalk::DEFAULT_TTR) { - $this->_client->useTube($tubeName); $result = $this->_client->useTube($tubeName)->put($tubeData, $tubePriority, $tubeDelay, $tubeTtr); return $result; @@ -206,18 +223,38 @@ private function _peek($tube, $method) { $peek = array(); } if ($peek) { - $peek['data'] = $this->_decodeDate($peek['data']); + $peek['data'] = $this->_decodeData($peek['data']); } return $peek; } - private function _decodeDate($pData) { - $this->_contentType = false; - $out = $pData; - $data = null; + /** + * Decodes job data based on user settings. + * + * @param string $pData Raw job data. + * @return mixed Decoded data or original data if no decoding applied/successful. + */ + private function _decodeData($pData) { // Renamed from _decodeDate for clarity + $this->_contentType = false; // Reset content type flag + $out = $pData; // Default output is the raw data + $data = null; // Intermediate decoded data + + // 1. Try Base64 Decode (if enabled in settings) + if ($this->settings->isBase64DecodeEnabled()) { + set_error_handler(array($this, 'exceptions_error_handler')); + try { + $data = base64_decode($pData); + } catch (Exception $e) { + $data = $e->getMessage(); + } + ob_get_clean(); + // restore old error handler + restore_error_handler(); + } - if (@$_COOKIE['isDisabledUnserialization'] != 1) { - $mixed = set_error_handler(array($this, 'exceptions_error_handler')); + // 2. Try Unserialize (if enabled in settings) + if ($this->settings->isUnserializationEnabled()) { + set_error_handler(array($this, 'exceptions_error_handler')); try { $data = unserialize($pData); } catch (Exception $e) { @@ -232,7 +269,8 @@ private function _decodeDate($pData) { $this->_contentType = 'php'; $out = $data; } else { - if (@$_COOKIE['isDisabledJsonDecode'] != 1) { + // 3. Try JSON Decode (if enabled in settings) + if ($this->settings->isJsonDecodeEnabled()) { $data = @json_decode($pData, true); } if ($data) { @@ -244,7 +282,7 @@ private function _decodeDate($pData) { } public function exceptions_error_handler($severity, $message, $filename, $lineno) { - echo 'Unserialize got a fatal error, please include the necessary files, or deactivate unserialization from Settings
'; + echo 'Unserialize or Base64decode got a fatal error, please include the necessary files, or deactivate unserialization from Settings (click to open)
'; return false; } diff --git a/lib/Pheanstalk.php b/lib/Pheanstalk.php index 03667e6..d85c450 100644 --- a/lib/Pheanstalk.php +++ b/lib/Pheanstalk.php @@ -26,7 +26,7 @@ class Pheanstalk */ public function __construct($host, $port = self::DEFAULT_PORT, $connectTimeout = null) { - $this->setConnection(new Pheanstalk_Connection($host, $port, $connectTimeout)); + $this->setConnection(new Pheanstalk_Connection($host, intval($port), $connectTimeout)); } /** @@ -63,6 +63,18 @@ public function delete($job) $this->_dispatch(new Pheanstalk_Command_DeleteCommand($job)); return $this; } + + /** + * Kicks job. + * + * @param object $job Pheanstalk_Job + * @chainable + */ + public function kickJob($job) + { + $this->_dispatch(new Pheanstalk_Command_KickJobCommand($job)); + return $this; + } /** * Remove the specified tube from the watchlist diff --git a/lib/Pheanstalk/Command/KickJobCommand.php b/lib/Pheanstalk/Command/KickJobCommand.php new file mode 100644 index 0000000..3bdf353 --- /dev/null +++ b/lib/Pheanstalk/Command/KickJobCommand.php @@ -0,0 +1,50 @@ +_job = $job; + } + + /* (non-phpdoc) + * @see Pheanstalk_Command::getCommandLine() + */ + + public function getCommandLine() { + return 'kick-job ' . $this->_job->getId(); + } + + /* (non-phpdoc) + * @see Pheanstalk_ResponseParser::parseRespose() + */ + public function parseResponse($responseLine, $responseData) { + if ($responseLine == Pheanstalk_Response::RESPONSE_NOT_FOUND) { + throw new Pheanstalk_Exception_ServerException(sprintf( + '%s: Job %d does not exist or is not in a kickable state.', $responseLine, $this->_job->getId() + )); + } elseif ($responseLine == Pheanstalk_Response::RESPONSE_KICKED) { + return $this->_createResponse(Pheanstalk_Response::RESPONSE_KICKED); + } else { + throw new Exception('Unhandled response: ' . $responseLine); + } + return $this->_createResponse($responseLine); + } + +} diff --git a/lib/include.php b/lib/include.php index a994390..ca8ee6a 100644 --- a/lib/include.php +++ b/lib/include.php @@ -1,674 +1,855 @@ -__init(); - $this->_main(); - } - - /** @return array */ - public function getServers() { - return $this->servers; - } - - public function getServerStats($server) { - try { - $interface = new BeanstalkInterface($server); - $stats = $interface->getServerStats(); - } catch (Pheanstalk_Exception_ConnectionException $e) { - $stats = array(); - } - - return $stats; - } - - public function getServerStatsGroups() { - return array( - 'binlog' => array( - 'binlog-current-index' => 'the index of the current binlog file being written to. If binlog is not active this value will be 0', - 'binlog-max-size' => 'the maximum size in bytes a binlog file is allowed to get before a new binlog file is opened', - 'binlog-oldest-index' => 'the index of the oldest binlog file needed to store the current jobs', - 'binlog-records-migrated' => 'the cumulative number of records written as part of compaction', - 'binlog-records-written' => 'the cumulative number of records written to the binlog', - ), - 'cmd' => array( - 'cmd-bury' => 'the cumulative number of bury commands', - 'cmd-delete' => 'the cumulative number of delete commands', - 'cmd-ignore' => 'the cumulative number of ignore commands', - 'cmd-kick' => 'the cumulative number of kick commands', - 'cmd-list-tube-used' => 'the cumulative number of list-tube-used commands', - 'cmd-list-tubes' => 'the cumulative number of list-tubes commands', - 'cmd-list-tubes-watched' => 'the cumulative number of list-tubes-watched commands', - 'cmd-pause-tube' => 'the cumulative number of pause-tube commands', - 'cmd-peek' => 'the cumulative number of peek commands', - 'cmd-peek-buried' => 'the cumulative number of peek-buried commands', - 'cmd-peek-delayed' => 'the cumulative number of peek-delayed commands', - 'cmd-peek-ready' => 'the cumulative number of peek-ready commands', - 'cmd-put' => 'the cumulative number of put commands', - 'cmd-release' => 'the cumulative number of release commands', - 'cmd-reserve' => 'the cumulative number of reserve commands', - 'cmd-stats' => 'the cumulative number of stats commands', - 'cmd-stats-job' => 'the cumulative number of stats-job commands', - 'cmd-stats-tube' => 'the cumulative number of stats-tube commands', - 'cmd-use' => 'the cumulative number of use commands', - 'cmd-watch' => 'the cumulative number of watch commands', - ), - 'current' => array( - 'current-connections' => 'the number of currently open connections', - 'current-jobs-buried' => 'the number of buried jobs', - 'current-jobs-delayed' => 'the number of delayed jobs', - 'current-jobs-ready' => 'the number of jobs in the ready queue', - 'current-jobs-reserved' => 'the number of jobs reserved by all clients', - 'current-jobs-urgent' => 'the number of ready jobs with priority < 1024', - 'current-producers' => 'the number of open connections that have each issued at least one put command', - 'current-tubes' => 'the number of currently-existing tubes', - 'current-waiting' => 'the number of open connections that have issued a reserve command but not yet received a response', - 'current-workers' => 'the number of open connections that have each issued at least one reserve command', - ), - 'other' => array( - 'hostname' => 'the hostname of the machine as determined by uname', - 'id' => 'a random id string for this server process, generated when each beanstalkd process starts', - 'job-timeouts' => 'the cumulative count of times a job has timed out', - 'max-job-size' => 'the maximum number of bytes in a job', - 'pid' => 'the process id of the server', - 'rusage-stime' => 'the cumulative system CPU time of this process in seconds and microseconds', - 'rusage-utime' => 'the cumulative user CPU time of this process in seconds and microseconds', - 'total-connections' => 'the cumulative count of connections', - 'total-jobs' => 'the cumulative count of jobs created', - 'uptime' => 'the number of seconds since this server process started running', - 'version' => 'the version string of the server', - ), - ); - } - - public function getTubeStatFields() { - return array( - 'current-jobs-urgent' => 'number of ready jobs with priority < 1024 in this tube', - 'current-jobs-ready' => 'number of jobs in the ready queue in this tube', - 'current-jobs-reserved' => 'number of jobs reserved by all clients in this tube', - 'current-jobs-delayed' => 'number of delayed jobs in this tube', - 'current-jobs-buried' => 'number of buried jobs in this tube', - 'total-jobs' => 'cumulative count of jobs created in this tube in the current beanstalkd process', - 'current-using' => 'number of open connections that are currently using this tube', - 'current-waiting' => 'number of open connections that have issued a reserve command while watching this tube but not yet received a response', - 'current-watching' => 'number of open connections that are currently watching this tube', - 'pause' => 'number of seconds the tube has been paused for', - 'cmd-delete' => 'cumulative number of delete commands for this tube', - 'cmd-pause-tube' => 'cumulative number of pause-tube commands for this tube', - 'pause-time-left' => 'number of seconds until the tube is un-paused', - ); - } - - public function getTubeStatGroups() { - return array( - 'current' => array( - 'current-jobs-buried', - 'current-jobs-delayed', - 'current-jobs-ready', - 'current-jobs-reserved', - 'current-jobs-urgent', - 'current-using', - 'current-waiting', - 'current-watching', - ), - 'other' => array( - 'cmd-delete', - 'cmd-pause-tube', - 'pause', - 'pause-time-left', - 'total-jobs', - ), - ); - } - - public function getTubeStatVisible() { - if (!empty($_COOKIE['tubefilter'])) { - return explode(',', $_COOKIE['tubefilter']); - } else { - return array( - 'current-jobs-buried', - 'current-jobs-delayed', - 'current-jobs-ready', - 'current-jobs-reserved', - 'current-jobs-urgent', - 'total-jobs', - ); - } - } - - public function getTubeStatValues($tube) { - // make sure, that rapid tube disappearance (eg: anonymous tubes, don't kill the interface, as they might be missing) - try { - return $this->interface->_client->statsTube($tube); - } catch (Pheanstalk_Exception_ServerException $ex) { - if (strpos($ex->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) !== false) { - return array(); - } else { - throw $ex; - } - } - } - - protected function __init() { - global $server, $action, $state, $count, $tube, $config, $tplMain, $tplBlock; - - $this->_globalVar = array( - 'server' => $server, - 'action' => $action, - 'state' => $state, - 'count' => $count, - 'tube' => $tube, - '_tplMain' => $tplMain, - '_tplBlock' => $tplBlock, - 'config' => $config); - $this->_tplVars = $this->_globalVar; - if (!in_array($this->_tplVars['_tplBlock'], array('allTubes'))) { - unset($this->_tplVars['_tplBlock']); - } - if (!in_array($this->_tplVars['_tplMain'], array('main', 'ajax'))) { - unset($this->_tplVars['_tplMain']); - } - if (empty($this->_tplVars['_tplMain'])) { - $this->_tplVars['_tplMain'] = 'main'; - } - - $this->servers = $config['servers']; - if (isset($_COOKIE['beansServers'])) { - foreach (explode(';', $_COOKIE['beansServers']) as $server) { - $this->servers[] = $server; - } - } - try { - $storage = new Storage($config['storage']); - } catch (Exception $ex) { - $this->_errors[] = $ex->getMessage(); - } - } - - public function getErrors() { - return $this->_errors; - } - - public function getTplVars($var = null) { - if (!empty($var)) { - $result = !empty($this->_tplVars[$var]) ? $this->_tplVars[$var] : null; - } else { - $result = $this->_tplVars; - } - - return $result; - } - - protected function deleteAllFromTube($state, $tube) { - try { - do { - switch ($state) { - case 'ready': - $job = $this->interface->_client->useTube($tube)->peekReady(); - break; - case 'delayed': - $job = $this->interface->_client->useTube($tube)->peekDelayed(); - break; - case 'buried': - $job = $this->interface->_client->useTube($tube)->peekBuried(); - break; - } - - if ($job) { - $this->interface->_client->delete($job); - set_time_limit(5); - } - } while (!empty($job)); - } catch (Exception $e) { - // there might be no jobs to peek at, and peekReady raises exception in this situation - echo $e->getMessage(); - } - } - - protected function _main() { - - - if (!isset($_GET['server'])) { - // execute methods without a server - if (isset($_GET['action']) && in_array($_GET['action'], array('serversRemove', 'manageSamples', 'deleteSample', 'editSample', 'newSample'))) { - $funcName = "_action" . ucfirst($this->_globalVar['action']); - if (method_exists($this, $funcName)) { - $this->$funcName(); - } - return; - } - return; - } - - try { - $this->interface = new BeanstalkInterface($this->_globalVar['server']); - - $this->_tplVars['tubes'] = $this->interface->getTubes(); - - $stats = $this->interface->getTubesStats(); - - $this->_tplVars['tubesStats'] = $stats; - $this->_tplVars['peek'] = $this->interface->peekAll($this->_globalVar['tube']); - $this->_tplVars['contentType'] = $this->interface->getContentType(); - if (!empty($_GET['action'])) { - $funcName = "_action" . ucfirst($this->_globalVar['action']); - if (method_exists($this, $funcName)) { - $this->$funcName(); - } - return; - } - } catch (Pheanstalk_Exception_ConnectionException $e) { - $this->_errors[] = 'The server is unavailable'; - } catch (Pheanstalk_Exception_ServerException $e) { - // if we get response not found, we just skip it (as the peekAll reached a tube which no longer existed) - if (strpos($e->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) === false) { - $this->_errors[] = $e->getMessage(); - } - } catch (Exception $e) { - $this->_errors[] = $e->getMessage(); - } - } - - protected function _actionKick() { - $this->interface->kick($this->_globalVar['tube'], $this->_globalVar['count']); - header( - sprintf('Location: index.php?server=%s&tube=%s', $this->_globalVar['server'], $this->_globalVar['tube'])); - exit(); - } - - protected function _actionDelete() { - switch ($this->_globalVar['state']) { - case 'ready': - $this->interface->deleteReady($this->_globalVar['tube']); - break; - case 'delayed': - $this->interface->deleteDelayed($this->_globalVar['tube']); - break; - case 'buried': - $this->interface->deleteBuried($this->_globalVar['tube']); - break; - } - - $this->_postDelete(); - } - - protected function _postDelete() { - $arr = $this->getTubeStatValues($this->_globalVar['tube']); - $availableJobs = $arr['current-jobs-urgent'] + $arr['current-jobs-ready'] + $arr['current-jobs-reserved'] + $arr['current-jobs-delayed'] + $arr['current-jobs-buried']; - if (empty($availableJobs)) { - // make sure we redirect to all tubes, as this tube no longer exists - $this->_globalVar['tube'] = null; - } - header( - sprintf('Location: index.php?server=%s&tube=%s', $this->_globalVar['server'], $this->_globalVar['tube'])); - exit(); - } - - protected function _actionDeleteAll($tube = null) { - if (empty($tube)) { - $tube = $this->_globalVar['tube']; - } - $this->deleteAllFromTube($this->_globalVar['state'], $tube); - $this->_postDelete(); - } - - protected function _actionServersRemove() { - $server = $_GET['removeServer']; - $this->servers = array_diff($this->servers, array($server)); - if (count($this->servers)) { - setcookie('beansServers', implode(';', $this->servers), time() + 86400 * 365); - } else { - // no servers, clear cookie - setcookie('beansServers', '', time() - 86400 * 365); - } - header('Location: index.php'); - exit(); - } - - protected function _actionAddjob() { - $result = array('result' => false); - - $tubeName = !empty($_POST['tubeName']) ? $_POST['tubeName'] : ''; - $tubeData = !empty($_POST['tubeData']) ? stripcslashes($_POST['tubeData']) : ''; - $tubePriority = !empty($_POST['tubePriority']) ? $_POST['tubePriority'] : ''; - $tubeDelay = !empty($_POST['tubeDelay']) ? $_POST['tubeDelay'] : ''; - $tubeTtr = !empty($_POST['tubeTtr']) ? $_POST['tubeTtr'] : ''; - - $id = $this->interface->addJob($tubeName, $tubeData, $tubePriority, $tubeDelay, $tubeTtr); - - if (!empty($result)) { - $result = array('result' => true, 'id' => $result); - } - - echo json_encode($result); - exit(); - } - - protected function _actionReloader() { - $this->_tplVars['_tplMain'] = 'ajax'; - $this->_tplVars['_tplBlock'] = 'allTubes'; - } - - protected function _actionClearTubes() { - if (is_array($_POST)) { - foreach ($_POST as $tube => $v) { - $states = array('ready', 'delayed', 'buried'); - foreach ($states as $state) { - $this->deleteAllFromTube($state, $tube); - } - } - } - echo json_encode(array('result' => true)); - exit(); - } - - protected function _actionPause() { - if ($this->_globalVar['count'] == -1) { - if (!@empty($_COOKIE['tubePauseSeconds'])) { - $this->_globalVar['count'] = $_COOKIE['tubePauseSeconds']; - } else { - $this->_globalVar['count'] = 3600; - } - } - $this->interface->pauseTube($this->_globalVar['tube'], $this->_globalVar['count']); - header( - sprintf('Location: index.php?server=%s&tube=%s', $this->_globalVar['server'], $this->_globalVar['tube'])); - exit(); - } - - protected function _actionAddSample() { - $success = false; - $error = ''; - $response = array('result' => &$success, 'error' => &$error); - if (isset($_POST['addsamplestate']) && isset($_POST['addsamplename']) && isset($_POST['tube']) && isset($_POST['tubes'])) { - try { - switch ($_POST['addsamplestate']) { - case 'ready': - $job = $this->interface->_client->useTube($_POST['tube'])->peekReady(); - break; - case 'delayed': - $job = $this->interface->_client->useTube($_POST['tube'])->peekDelayed(); - break; - case 'buried': - $job = $this->interface->_client->useTube($_POST['tube'])->peekBuried(); - break; - } - if ($job) { - $res = $this->_storeSampleJob($_POST, $job->getData()); - if ($res === true) { - $success = true; - } else { - $error = $res; - } - } else { - $error = 'Invalid state option'; - } - } catch (Exception $e) { - // there might be no jobs to peek at, and peekReady raises exception in this situation - $error = $e->getMessage(); - } - } else { - $error = 'Required fields are not set'; - } - echo json_encode($response); - exit(); - } - - protected function _actionLoadSample() { - $key = $_GET['key']; - if (!empty($key)) { - $storage = new Storage($this->_globalVar['config']['storage']); - $job = $storage->load($key); - if ($job) { - $this->interface->addJob($this->_globalVar['tube'], $job['data']); - } - } - if (isset($_GET['redirect'])) { - $_SESSION['info'] = 'Job placed on tube'; - header(sprintf('Location: %s', $_GET['redirect'])); - } else { - header(sprintf('Location: index.php?server=%s&tube=%s', $this->_globalVar['server'], $this->_globalVar['tube'])); - } - exit(); - } - - protected function _actionManageSamples() { - $this->_tplVars['_tplMain'] = 'main'; - $this->_tplVars['_tplPage'] = 'sampleJobsManage'; - } - - protected function _actionEditSample() { - $this->_tplVars['_tplMain'] = 'main'; - $this->_tplVars['_tplPage'] = 'sampleJobsEdit'; - $key = $_GET['key']; - if (!empty($key)) { - $storage = new Storage($this->_globalVar['config']['storage']); - $job = $storage->load($key); - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (isset($_POST['jobdata']) && isset($_POST['name']) && isset($_POST['tubes'])) { - $oldjob = $job; - $storage->delete($key); - $job['name'] = $_POST['name']; - $job['tubes'] = $_POST['tubes']; - $job['data'] = htmlspecialchars_decode($_POST['jobdata']); - if ($storage->saveJob($job)) { - header('Location: index.php?action=manageSamples'); - } else { - $storage->saveJob($oldjob); - $this->_tplVars['error'] = $storage->getError(); - } - } else { - $job['name'] = @$_POST['name']; - $job['data'] = @$_POST['jobdata']; - $job['tubes'] = @$_POST['tubes']; - $this->_tplVars['error'] = 'Required fields are not set'; - } - } - if ($job) { - $this->_tplVars['job'] = $job; - } else { - $this->_errors[] = 'Cannot locate job'; - return; - } - } else { - $this->_errors[] = 'The requested key is invalid'; - return; - } - $serverTubes = array(); - if (is_array($this->servers)) { - foreach ($this->servers as $server) { - try { - $interface = new BeanstalkInterface($server); - $tubes = $interface->getTubes(); - if (is_array($tubes)) { - $serverTubes[$server] = $tubes; - } - } catch (Exception $e) { - - } - } - } - if (empty($serverTubes)) { - $this->_errors[] = 'No tubes were found, please connect a server.'; - return; - } - $this->_tplVars['serverTubes'] = $serverTubes; - } - - protected function _actionNewSample() { - $this->_tplVars['_tplMain'] = 'main'; - $this->_tplVars['_tplPage'] = 'sampleJobsEdit'; - $this->_tplVars['isNewRecord'] = true; - $storage = new Storage($this->_globalVar['config']['storage']); - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if (isset($_POST['jobdata']) && isset($_POST['name']) && isset($_POST['tubes'])) { - $job['name'] = $_POST['name']; - $job['tubes'] = $_POST['tubes']; - $job['data'] = htmlspecialchars_decode($_POST['jobdata']); - if ($storage->saveJob($job)) { - header('Location: index.php?action=manageSamples'); - } else { - $this->_tplVars['error'] = $storage->getError(); - } - } else { - $job['name'] = @$_POST['name']; - $job['data'] = @$_POST['jobdata']; - $job['tubes'] = @$_POST['tubes']; - $this->_tplVars['error'] = 'Required fields are not set'; - } - } - - $serverTubes = array(); - if (is_array($this->servers)) { - foreach ($this->servers as $server) { - try { - $interface = new BeanstalkInterface($server); - $tubes = $interface->getTubes(); - if (is_array($tubes)) { - $serverTubes[$server] = $tubes; - } - } catch (Exception $e) { - - } - } - } - if (empty($serverTubes)) { - $this->_errors[] = 'No tubes were found, please connect a server.'; - return; - } - $this->_tplVars['serverTubes'] = $serverTubes; - } - - protected function _actionDeleteSample() { - $key = $_GET['key']; - if (!empty($key)) { - $storage = new Storage($this->_globalVar['config']['storage']); - $job = $storage->load($key); - if ($job) { - $storage->delete($key); - } - } - header('Location: index.php?action=manageSamples'); - exit(); - } - - protected function _actionMoveJobsTo() { - global $server, $tube, $state; - $destTube = (isset($_GET['destTube'])) ? $_GET['destTube'] : null; - $destState = (isset($_GET['destState'])) ? $_GET['destState'] : null; - if (!empty($destTube) && in_array($state, array('ready', 'delayed', 'buried'))) { - $this->moveJobsFromTo($server, $tube, $state, $destTube); - } - if (!empty($destState)) { - $this->moveJobsToState($server, $tube, $state, $destState); - } - } - - private function _storeSampleJob($post, $jobData) { - $storage = new Storage($this->_globalVar['config']['storage']); - $job_array = array(); - $job_array['name'] = trim($post['addsamplename']); - $job_array['tubes'] = $post['tubes']; - $job_array['data'] = $jobData; - if ($storage->saveJob($job_array)) { - return true; - } else { - return $storage->getError(); - } - } - - public function getSampleJobs($tube = null) { - $storage = new Storage($this->_globalVar['config']['storage']); - if ($tube) { - return $storage->getJobsForTube($tube); - } else { - return $storage->getJobs(); - } - } - - private function moveJobsFromTo($server, $tube, $state, $destTube) { - try { - do { - switch ($state) { - case 'ready': - $job = $this->interface->_client->useTube($tube)->peekReady(); - break; - case 'delayed': - $job = $this->interface->_client->useTube($tube)->peekDelayed(); - break; - case 'buried': - $job = $this->interface->_client->useTube($tube)->peekBuried(); - break; - } - - if ($job) { - $this->interface->addJob($destTube, $job->getData()); - $this->interface->_client->delete($job); - set_time_limit(5); - } - } while (!empty($job)); - } catch (Exception $e) { - // there might be no jobs to peek at, and peekReady raises exception in this situation - } - header(sprintf('Location: index.php?server=%s&tube=%s', $server, $destTube)); - } - - private function moveJobsToState($server, $tube, $state, $destState) { - try { - do { - $job = null; - switch ($state) { - case 'ready': - $job = $this->interface->_client->watch($tube)->reserve(0); - break; - default: - return; - } - - if ($job) { - switch ($destState) { - case 'buried': - $this->interface->_client->bury($job); - break; - default: - return; - } - set_time_limit(5); - } - } while (!empty($job)); - } catch (Exception $e) { - // there might be no jobs to peek at, and peekReady raises exception in this situation - } - header(sprintf('Location: index.php?server=%s&tube=%s', $server, $tube)); - } - -} +__init(); + $this->_main(); + } + + /** @return array */ + public function getServers() { + return array_merge($this->serversConfig, $this->serversEnv, $this->serversCookie); + } + + /** @return array */ + public function getServersConfig() { + return $this->serversConfig; + } + + /** @return array */ + public function getServersEnv() { + return $this->serversEnv; + } + + /** @return array */ + public function getServersCookie() { + return $this->serversCookie; + } + + public function getServerStats($server) { + try { + $interface = new BeanstalkInterface($server); + $stats = $interface->getServerStats(); + } catch (Pheanstalk_Exception_ConnectionException $e) { + $stats = array(); + } + + return $stats; + } + + public function getServerStatsGroups() { + return array( + 'binlog' => array( + 'binlog-current-index' => 'the index of the current binlog file being written to. If binlog is not active this value will be 0', + 'binlog-max-size' => 'the maximum size in bytes a binlog file is allowed to get before a new binlog file is opened', + 'binlog-oldest-index' => 'the index of the oldest binlog file needed to store the current jobs', + 'binlog-records-migrated' => 'the cumulative number of records written as part of compaction', + 'binlog-records-written' => 'the cumulative number of records written to the binlog', + ), + 'cmd' => array( + 'cmd-bury' => 'the cumulative number of bury commands', + 'cmd-delete' => 'the cumulative number of delete commands', + 'cmd-ignore' => 'the cumulative number of ignore commands', + 'cmd-kick' => 'the cumulative number of kick commands', + 'cmd-list-tube-used' => 'the cumulative number of list-tube-used commands', + 'cmd-list-tubes' => 'the cumulative number of list-tubes commands', + 'cmd-list-tubes-watched' => 'the cumulative number of list-tubes-watched commands', + 'cmd-pause-tube' => 'the cumulative number of pause-tube commands', + 'cmd-peek' => 'the cumulative number of peek commands', + 'cmd-peek-buried' => 'the cumulative number of peek-buried commands', + 'cmd-peek-delayed' => 'the cumulative number of peek-delayed commands', + 'cmd-peek-ready' => 'the cumulative number of peek-ready commands', + 'cmd-put' => 'the cumulative number of put commands', + 'cmd-release' => 'the cumulative number of release commands', + 'cmd-reserve' => 'the cumulative number of reserve commands', + 'cmd-stats' => 'the cumulative number of stats commands', + 'cmd-stats-job' => 'the cumulative number of stats-job commands', + 'cmd-stats-tube' => 'the cumulative number of stats-tube commands', + 'cmd-use' => 'the cumulative number of use commands', + 'cmd-watch' => 'the cumulative number of watch commands', + ), + 'current' => array( + 'current-connections' => 'the number of currently open connections', + 'current-jobs-buried' => 'the number of buried jobs', + 'current-jobs-delayed' => 'the number of delayed jobs', + 'current-jobs-ready' => 'the number of jobs in the ready queue', + 'current-jobs-reserved' => 'the number of jobs reserved by all clients', + 'current-jobs-urgent' => 'the number of ready jobs with priority < 1024', + 'current-producers' => 'the number of open connections that have each issued at least one put command', + 'current-tubes' => 'the number of currently-existing tubes', + 'current-waiting' => 'the number of open connections that have issued a reserve command but not yet received a response', + 'current-workers' => 'the number of open connections that have each issued at least one reserve command', + ), + 'other' => array( + 'hostname' => 'the hostname of the machine as determined by uname', + 'id' => 'a random id string for this server process, generated when each beanstalkd process starts', + 'job-timeouts' => 'the cumulative count of times a job has timed out', + 'max-job-size' => 'the maximum number of bytes in a job', + 'pid' => 'the process id of the server', + 'rusage-stime' => 'the cumulative system CPU time of this process in seconds and microseconds', + 'rusage-utime' => 'the cumulative user CPU time of this process in seconds and microseconds', + 'total-connections' => 'the cumulative count of connections', + 'total-jobs' => 'the cumulative count of jobs created', + 'uptime' => 'the number of seconds since this server process started running', + 'version' => 'the version string of the server', + ), + ); + } + + public function getTubeStatFields() { + return array( + 'current-jobs-urgent' => 'number of ready jobs with priority < 1024 in this tube', + 'current-jobs-ready' => 'number of jobs in the ready queue in this tube', + 'current-jobs-reserved' => 'number of jobs reserved by all clients in this tube', + 'current-jobs-delayed' => 'number of delayed jobs in this tube', + 'current-jobs-buried' => 'number of buried jobs in this tube', + 'total-jobs' => 'cumulative count of jobs created in this tube in the current beanstalkd process', + 'current-using' => 'number of open connections that are currently using this tube', + 'current-waiting' => 'number of open connections that have issued a reserve command while watching this tube but not yet received a response', + 'current-watching' => 'number of open connections that are currently watching this tube', + 'pause' => 'number of seconds the tube has been paused for', + 'cmd-delete' => 'cumulative number of delete commands for this tube', + 'cmd-pause-tube' => 'cumulative number of pause-tube commands for this tube', + 'pause-time-left' => 'number of seconds until the tube is un-paused', + ); + } + + public function getTubeStatGroups() { + return array( + 'current' => array( + 'current-jobs-buried', + 'current-jobs-delayed', + 'current-jobs-ready', + 'current-jobs-reserved', + 'current-jobs-urgent', + 'current-using', + 'current-waiting', + 'current-watching', + ), + 'other' => array( + 'cmd-delete', + 'cmd-pause-tube', + 'pause', + 'pause-time-left', + 'total-jobs', + ), + ); + } + + public function getTubeStatVisible() { + if (!empty($_COOKIE['tubefilter'])) { + return explode(',', $_COOKIE['tubefilter']); + } else { + return array( + 'current-jobs-buried', + 'current-jobs-delayed', + 'current-jobs-ready', + 'current-jobs-reserved', + 'current-jobs-urgent', + 'total-jobs', + ); + } + } + + public function getTubeStatValues($tube) { + // make sure, that rapid tube disappearance (eg: anonymous tubes, don't kill the interface, as they might be missing) + try { + return $this->interface->_client->statsTube($tube); + } catch (Pheanstalk_Exception_ServerException $ex) { + if (strpos($ex->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) !== false) { + return array(); + } else { + throw $ex; + } + } + } + + public function getSearchResult() { + return $this->searchResults; + } + + protected function __init() { + $this->_globalVar = array( + 'server' => $GLOBALS['server'], + 'action' => $GLOBALS['action'], + 'state' => $GLOBALS['state'], + 'count' => $GLOBALS['count'], + 'tube' => $GLOBALS['tube'], + '_tplMain' => $GLOBALS['tplMain'], + '_tplBlock' => $GLOBALS['tplBlock'], + 'config' => $GLOBALS['config']); + $this->_tplVars = $this->_globalVar; + if (!in_array($this->_tplVars['_tplBlock'], array('allTubes', 'serversList'))) { + unset($this->_tplVars['_tplBlock']); + } + if (!in_array($this->_tplVars['_tplMain'], array('main', 'ajax'))) { + unset($this->_tplVars['_tplMain']); + } + if (empty($this->_tplVars['_tplMain'])) { + $this->_tplVars['_tplMain'] = 'main'; + } + + foreach ($GLOBALS['config']['servers'] as $key => $server) { + $this->serversConfig[$key] = $server; + } + if (false !== getenv('BEANSTALK_SERVERS')) { + foreach (explode(',', getenv('BEANSTALK_SERVERS')) as $key => $server) { + $this->serversEnv[$key] = $server; + } + } + if (isset($_COOKIE['beansServers'])) { + foreach (explode(';', $_COOKIE['beansServers']) as $key => $server) { + $this->serversCookie[$key] = $server; + } + } + try { + $storage = new Storage($GLOBALS['config']['storage']); + } catch (Exception $ex) { + $this->_errors[] = $ex->getMessage(); + } + } + + public function getErrors() { + return $this->_errors; + } + + public function getTplVars($var = null) { + if (!empty($var)) { + $result = !empty($this->_tplVars[$var]) ? $this->_tplVars[$var] : null; + } else { + $result = $this->_tplVars; + } + + return $result; + } + + protected function deleteAllFromTube($state, $tube) { + try { + $this->interface->_client->useTube($tube); + do { + switch ($state) { + case 'ready': + $job = $this->interface->_client->peekReady(); + break; + case 'delayed': + try { + $ready = $this->interface->_client->peekReady(); + if ($ready) { + $this->_errors[] = 'Cannot delete Delayed until there are Ready messages on this tube'; + return; + } + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + if (strpos($e->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) === false) { + throw $e; + } + } + try { + $bury = $this->interface->_client->peekBuried(); + if ($bury) { + $this->_errors[] = 'Cannot delete Delayed until there are Bury messages on this tube'; + return; + } + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + if (strpos($e->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) === false) { + throw $e; + } + } + $job = $this->interface->_client->peekDelayed(); + if ($job) { + //when we found job with Delayed, kick all messages, to be ready, so that we can Delete them. + $this->interface->kick($tube, 100000000); + $this->deleteAllFromTube('ready', $tube); + return; + } + break; + case 'buried': + $job = $this->interface->_client->peekBuried(); + break; + } + + if ($job) { + $this->interface->_client->delete($job); + set_time_limit(5); + } + } while (!empty($job)); + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + // skip not found exception + if (strpos($e->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) === false) { + $this->_errors[] = $e->getMessage(); + } + } + } + + protected function _main() { + + + if (!isset($_GET['server'])) { + // execute methods without a server + if (isset($_GET['action']) && in_array($_GET['action'], array('serversRemove', 'manageSamples', 'deleteSample', 'editSample', 'newSample'))) { + $funcName = "_action" . ucfirst($this->_globalVar['action']); + if (method_exists($this, $funcName)) { + $this->$funcName(); + } + return; + } + return; + } + + try { + $this->interface = new BeanstalkInterface($this->_globalVar['server']); + + $this->_tplVars['tubes'] = $this->interface->getTubes(); + + $stats = $this->interface->getTubesStats(); + + $this->_tplVars['tubesStats'] = $stats; + $this->_tplVars['peek'] = $this->interface->peekAll($this->_globalVar['tube']); + $this->_tplVars['contentType'] = $this->interface->getContentType(); + if (!empty($_GET['action'])) { + $funcName = "_action" . ucfirst($this->_globalVar['action']); + if (method_exists($this, $funcName)) { + $this->$funcName(); + } + return; + } + } catch (Pheanstalk_Exception_ConnectionException $e) { + $this->_errors[] = 'The server is unavailable'; + } catch (Pheanstalk_Exception_ServerException $e) { + // if we get response not found, we just skip it (as the peekAll reached a tube which no longer existed) + if (strpos($e->getMessage(), Pheanstalk_Response::RESPONSE_NOT_FOUND) === false) { + $this->_errors[] = $e->getMessage(); + } + } catch (Exception $e) { + $this->_errors[] = $e->getMessage(); + } + } + + protected function _actionKick() { + $this->interface->kick($this->_globalVar['tube'], $this->_globalVar['count']); + header( + sprintf('Location: ./?server=%s&tube=%s', $this->_globalVar['server'], urlencode($this->_globalVar['tube']))); + exit(); + } + + protected function _actionKickJob() { + $job = $this->interface->_client->peek(intval($_GET['jobid'])); + if ($job) { + $this->interface->_client->kickJob($job); + } + header( + sprintf('Location: ./?server=%s&tube=%s', $this->_globalVar['server'], urlencode($this->_globalVar['tube']))); + exit(); + } + + protected function _actionDelete() { + switch ($this->_globalVar['state']) { + case 'ready': + $this->interface->deleteReady($this->_globalVar['tube']); + break; + case 'delayed': + $this->interface->deleteDelayed($this->_globalVar['tube']); + break; + case 'buried': + $this->interface->deleteBuried($this->_globalVar['tube']); + break; + } + + $this->_postDelete(); + } + + protected function _actionDeleteJob() { + $job = $this->interface->_client->peek(intval($_GET['jobid'])); + if ($job) { + $this->interface->_client->delete($job); + } + $this->_postDelete(); + } + + protected function _postDelete() { + $arr = $this->getTubeStatValues($this->_globalVar['tube']); + $availableJobs = $arr['current-jobs-urgent'] + $arr['current-jobs-ready'] + $arr['current-jobs-reserved'] + $arr['current-jobs-delayed'] + $arr['current-jobs-buried']; + if (empty($availableJobs)) { + // make sure we redirect to all tubes, as this tube no longer exists + $this->_globalVar['tube'] = null; + } + header( + sprintf('Location: ./?server=%s&tube=%s', $this->_globalVar['server'], urlencode($this->_globalVar['tube'] ?? ''))); + exit(); + } + + protected function _actionDeleteAll($tube = null) { + if (empty($tube)) { + $tube = $this->_globalVar['tube']; + } + $this->deleteAllFromTube($this->_globalVar['state'], $tube); + if (empty($this->_errors)) { + $this->_postDelete(); + } + } + + protected function _actionServersRemove() { + $server = $_GET['removeServer']; + $cookie_servers = array_diff($this->getServersCookie(), array($server)); + if (count($cookie_servers)) { + setcookie('beansServers', implode(';', $cookie_servers), time() + 86400 * 365); + } else { + // no servers, clear cookie + setcookie('beansServers', '', time() - 86400 * 365); + } + header('Location: ./?'); + exit(); + } + + protected function _actionAddjob() { + $result = array('result' => false); + + $tubeName = !empty($_POST['tubeName']) ? $_POST['tubeName'] : ''; + $tubeData = !empty($_POST['tubeData']) ? stripcslashes($_POST['tubeData']) : ''; + $tubePriority = !empty($_POST['tubePriority']) ? $_POST['tubePriority'] : ''; + $tubeDelay = !empty($_POST['tubeDelay']) ? $_POST['tubeDelay'] : ''; + $tubeTtr = !empty($_POST['tubeTtr']) ? $_POST['tubeTtr'] : ''; + + $id = $this->interface->addJob($tubeName, $tubeData, $tubePriority, $tubeDelay, $tubeTtr); + + if (!empty($id)) { + $result = array('result' => true, 'id' => $id); + } + + echo json_encode($result); + exit(); + } + + protected function _actionReloader() { + $this->_tplVars['_tplMain'] = 'ajax'; + $this->_tplVars['_tplBlock'] = 'allTubes'; + } + + protected function _actionClearTubes() { + if (is_array($_POST)) { + foreach ($_POST as $tube => $v) { + $states = array('ready', 'delayed', 'buried'); + foreach ($states as $state) { + $this->deleteAllFromTube($state, $tube); + } + } + } + echo json_encode(array('result' => true)); + exit(); + } + + protected function _actionPause() { + $delayParam = $this->_globalVar['count']; // Get delay from URL parameter ('count') + + if ($delayParam === '-1') { + // If URL param is -1, get the effective setting (Cookie or Config default) + $settings = new Settings(); + $settingValue = $settings->getTubePauseSeconds(); + + // If the setting itself is -1 (meaning use beanstalkd default), set delay to 3600 + if ($settingValue == -1) { + $delay = 3600; // Beanstalkd default pause time (1 hour) + } else { + // Otherwise, use the non-negative value from settings (cookie or config) + $delay = max(0, $settingValue); // Ensure it's not negative if config/cookie somehow has < 0 + } + } else { + // Use the value directly from the URL parameter, ensuring it's a non-negative integer + $delay = max(0, intval($delayParam)); + } + $this->interface->pauseTube($this->_globalVar['tube'], $delay); + header( + sprintf('Location: ./?server=%s&tube=%s', $this->_globalVar['server'], urlencode($this->_globalVar['tube']))); + exit(); + } + + protected function _actionAddSample() { + $success = false; + $error = ''; + $response = array('result' => &$success, 'error' => &$error); + if (isset($_POST['addsamplejobid']) && isset($_POST['addsamplename']) && isset($_POST['tube']) && isset($_POST['tubes'])) { + try { + $job = $this->interface->_client->peek(intval($_POST['addsamplejobid'])); + if ($job) { + $res = $this->_storeSampleJob($_POST, $job->getData()); + if ($res === true) { + $success = true; + } else { + $error = $res; + } + } else { + $error = 'Invalid state option'; + } + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + $error = $e->getMessage(); + } + } else { + $error = 'Required fields are not set'; + } + echo json_encode($response); + exit(); + } + + protected function _actionLoadSample() { + $key = $_GET['key']; + if (!empty($key)) { + $storage = new Storage($this->_globalVar['config']['storage']); + $job = $storage->load($key); + if ($job) { + $this->interface->addJob($this->_globalVar['tube'], $job['data']); + } + } + if (isset($_GET['redirect'])) { + $_SESSION['info'] = 'Job placed on tube'; + header(sprintf('Location: %s', $_GET['redirect'])); + } else { + header(sprintf('Location: ./?server=%s&tube=%s', $this->_globalVar['server'], urlencode($this->_globalVar['tube']))); + } + exit(); + } + + protected function _actionManageSamples() { + $this->_tplVars['_tplMain'] = 'main'; + $this->_tplVars['_tplPage'] = 'sampleJobsManage'; + } + + protected function _actionEditSample() { + $this->_tplVars['_tplMain'] = 'main'; + $this->_tplVars['_tplPage'] = 'sampleJobsEdit'; + $key = $_GET['key']; + if (!empty($key)) { + $storage = new Storage($this->_globalVar['config']['storage']); + $job = $storage->load($key); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if (isset($_POST['jobdata']) && isset($_POST['name']) && isset($_POST['tubes'])) { + $oldjob = $job; + $storage->delete($key); + $job['name'] = $_POST['name']; + $job['tubes'] = $_POST['tubes']; + $job['data'] = htmlspecialchars_decode($_POST['jobdata']); + if ($storage->saveJob($job)) { + header('Location: ./?action=manageSamples'); + } else { + $storage->saveJob($oldjob); + $this->_tplVars['error'] = $storage->getError(); + } + } else { + $job['name'] = @$_POST['name']; + $job['data'] = @$_POST['jobdata']; + $job['tubes'] = @$_POST['tubes']; + $this->_tplVars['error'] = 'Required fields are not set'; + } + } + if ($job) { + $this->_tplVars['job'] = $job; + } else { + $this->_errors[] = 'Cannot locate job'; + return; + } + } else { + $this->_errors[] = 'The requested key is invalid'; + return; + } + $serverTubes = array(); + if (is_array($this->getServers())) { + foreach ($this->getServers() as $server) { + try { + $interface = new BeanstalkInterface($server); + $tubes = $interface->getTubes(); + if (is_array($tubes)) { + $serverTubes[$server] = $tubes; + } + } catch (Exception $e) { + + } + } + } + if (empty($serverTubes)) { + $this->_errors[] = 'No tubes were found, please connect a server.'; + return; + } + $this->_tplVars['serverTubes'] = $serverTubes; + } + + protected function _actionNewSample() { + $this->_tplVars['_tplMain'] = 'main'; + $this->_tplVars['_tplPage'] = 'sampleJobsEdit'; + $this->_tplVars['isNewRecord'] = true; + $storage = new Storage($this->_globalVar['config']['storage']); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if (isset($_POST['jobdata']) && isset($_POST['name']) && isset($_POST['tubes'])) { + $job['name'] = $_POST['name']; + $job['tubes'] = $_POST['tubes']; + $job['data'] = htmlspecialchars_decode($_POST['jobdata']); + if ($storage->saveJob($job)) { + header('Location: ./?action=manageSamples'); + } else { + $this->_tplVars['error'] = $storage->getError(); + } + } else { + $job['name'] = @$_POST['name']; + $job['data'] = @$_POST['jobdata']; + $job['tubes'] = @$_POST['tubes']; + $this->_tplVars['error'] = 'Required fields are not set'; + } + } + + $serverTubes = array(); + if (is_array($this->getServers())) { + foreach ($this->getServers() as $server) { + try { + $interface = new BeanstalkInterface($server); + $tubes = $interface->getTubes(); + if (is_array($tubes)) { + $serverTubes[$server] = $tubes; + } + } catch (Exception $e) { + + } + } + } + if (empty($serverTubes)) { + $this->_errors[] = 'No tubes were found, please connect a server.'; + return; + } + $this->_tplVars['serverTubes'] = $serverTubes; + } + + protected function _actionDeleteSample() { + $key = $_GET['key']; + if (!empty($key)) { + $storage = new Storage($this->_globalVar['config']['storage']); + $job = $storage->load($key); + if ($job) { + $storage->delete($key); + } + } + header('Location: ./?action=manageSamples'); + exit(); + } + + protected function _actionMoveJobsTo() { + $destServer = (isset($_GET['server'])) ? $_GET['server'] : null; + $destTube = (isset($_GET['destTube'])) ? $_GET['destTube'] : null; + $destState = (isset($_GET['destState'])) ? $_GET['destState'] : null; + if (!empty($destTube) && in_array($GLOBALS['state'], array('ready', 'delayed', 'buried'))) { + $this->moveJobsFromTo($destServer, $GLOBALS['tube'], $GLOBALS['state'], $destTube); + } + if (!empty($destState)) { + $this->moveJobsToState($destServer, $GLOBALS['tube'], $GLOBALS['state'], $destState); + } + } + + protected function _actionSearch() { + $this->actionTimeStart = microtime(true); + $timelimit_in_seconds = 15; + $searchStr = (isset($_GET['searchStr'])) ? $_GET['searchStr'] : null; + $states = array('ready', 'delayed', 'buried'); + $jobList = array(); + $limit = null; + + if ($searchStr === null or $searchStr === '') + return false; + + if (isset($_GET['limit'])) { + $limit = intval($_GET['limit']); + } + + foreach ($states as $state) { + $jobList[$state] = $this->findJobsByState($GLOBALS['tube'], $state, $searchStr, $limit); + $jobList['total'] += count($jobList[$state]); + } + + $this->searchResults = $jobList; + } + + private function findJobsByState($tube, $state, $searchStr, $limit = 25) { + $jobList = array(); + $job = null; + + try { + $stats = $this->interface->getServerStats(); + } catch (Exception $e) { + return $jobList; + } + + $ready = $stats['current-jobs-ready']['value']; + $reserved = $stats['current-jobs-reserved']['value']; + $delayed = $stats['current-jobs-delayed']['value']; + $buried = $stats['current-jobs-buried']['value']; + $deleted = $stats['cmd-delete']['value']; + + try { + switch ($state) { + case 'ready': + $job = $this->interface->_client->useTube($tube)->peekReady(); + break; + case 'delayed': + $job = $this->interface->_client->useTube($tube)->peekDelayed(); + break; + case 'buried': + $job = $this->interface->_client->useTube($tube)->peekBuried(); + break; + } + } catch (Exception $e) { + + } + + if ($job === null) + return $jobList; + + $jobList = array(); + $lastId = $ready + $reserved + $delayed + $buried + $deleted; + + $added = 0; + for ($id = $job->getId(); $id <= $lastId; $id++) { + try { + /** @var Pheanstalk_Job $job */ + $job = $this->interface->_client->peek($id); + if ($job) { + $jobStats = $this->interface->_client->statsJob($job); + if ($jobStats->tube === $tube && + $jobStats->state === $state && + strpos($job->getData(), $searchStr) !== false + ) { + $jobList[$id] = $job; + $added++; + } + } + } catch (Pheanstalk_Exception_ServerException $e) { + + } + if ($added >= $limit || (microtime(true) - $this->actionTimeStart) > $limit) { + break; + } + } + + return $jobList; + } + + private function _storeSampleJob($post, $jobData) { + $storage = new Storage($this->_globalVar['config']['storage']); + $job_array = array(); + $job_array['name'] = trim($post['addsamplename']); + $job_array['tubes'] = $post['tubes']; + $job_array['data'] = $jobData; + if ($storage->saveJob($job_array)) { + return true; + } else { + return $storage->getError(); + } + } + + public function getSampleJobs($tube = null) { + $storage = new Storage($this->_globalVar['config']['storage']); + if ($tube) { + return $storage->getJobsForTube($tube); + } else { + return $storage->getJobs(); + } + } + + private function moveJobsFromTo($server, $tube, $state, $destTube) { + try { + do { + $this->interface->_client->useTube($tube); + switch ($state) { + case 'ready': + $job = $this->interface->_client->peekReady(); + break; + case 'delayed': + $job = $this->interface->_client->peekDelayed(); + break; + case 'buried': + $job = $this->interface->_client->peekBuried(); + break; + } + + if ($job) { + $this->interface->addJob($destTube, $job->getData()); + $this->interface->_client->delete($job); + set_time_limit(5); + } + } while (!empty($job)); + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + } + header(sprintf('Location: ./?server=%s&tube=%s', $server, urlencode($destTube))); + } + + private function moveJobsToState($server, $tube, $state, $destState) { + try { + do { + $job = null; + switch ($state) { + case 'ready': + $job = $this->interface->_client->watch($tube)->reserve(0); + break; + default: + return; + } + + if ($job) { + switch ($destState) { + case 'buried': + $this->interface->_client->bury($job); + break; + default: + return; + } + set_time_limit(5); + } + } while (!empty($job)); + } catch (Exception $e) { + // there might be no jobs to peek at, and peekReady raises exception in this situation + } + header(sprintf('Location: ./?server=%s&tube=%s', $server, urlencode($tube))); + } + +} diff --git a/lib/tpl/ajax.php b/lib/tpl/ajax.php index 25c463b..b40ec09 100644 --- a/lib/tpl/ajax.php +++ b/lib/tpl/ajax.php @@ -1 +1 @@ - \ No newline at end of file + diff --git a/lib/tpl/allTubes.php b/lib/tpl/allTubes.php index 03b57d1..90da55f 100644 --- a/lib/tpl/allTubes.php +++ b/lib/tpl/allTubes.php @@ -20,16 +20,34 @@ - - - + + $arr) { + $tubeStats[$key] = $arr['value']; + } + ?> + + - getTubeStatValues($tubeItem) ?> $item): - $markHidden = !in_array($key, $visible) ? ' class="hide"' : ''; + $classes = array("td-$key"); + if (!in_array($key, $visible)) { + $classes[] = 'hide'; + } + if (isset($tubeStats[$key]) && $tubeStats[$key] != '0') { + $classes[] = 'hasValue'; + } + $cssClass = ''; + if (count($classes) > 0) { + $cssClass = ' class = "' . join(' ', $classes) . '"'; + } ?> - > + > @@ -37,4 +55,4 @@ - \ No newline at end of file + diff --git a/lib/tpl/currentTube.php b/lib/tpl/currentTube.php index 9479a97..c0509c6 100644 --- a/lib/tpl/currentTube.php +++ b/lib/tpl/currentTube.php @@ -1,183 +1,6 @@ getTubeStatFields(); -$groups = $console->getTubeStatGroups(); -$visible = $console->getTubeStatVisible(); -$sampleJobs = $console->getSampleJobs($tube); - -if (!@empty($_COOKIE['tubePauseSeconds'])) { - $tubePauseSeconds = intval($_COOKIE['tubePauseSeconds']); +if (isset($action) && $action == 'search') { + include_once('currentTubeSearchResults.php'); } else { - $tubePauseSeconds = 3600; + include_once('currentTubeJobs.php'); } -?> -
-
-
- - - - - $item): - $markHidden = !in_array($key, $visible) ? ' class="hide"' : ''; - ?> - name="" title=""> - - - - - - - - getTubeStatValues($tubeItem) ?> - $item): - $markHidden = !in_array($key, $visible) ? ' class="hide"' : ''; - ?> - > - - - - -
name
-
-
- -
- - -Actions:  - Kick 1 job - Kick 10 job - - Pause tube Unpause tube -      -
- Add job - - -
- - $job): ?> -
-
-

Next job in "" state

-
-
- - -
-
- - - - - - - - - $value): ?> - - - - - - -
Stats: 
-
-
-
-
- Job data: -
- -
-
- Add to - samples - -
- - -
- Delete all jobs - Delete -
-
- - -
-
-
-
- - empty - - diff --git a/lib/tpl/currentTubeJobs.php b/lib/tpl/currentTubeJobs.php new file mode 100644 index 0000000..53dd30f --- /dev/null +++ b/lib/tpl/currentTubeJobs.php @@ -0,0 +1,16 @@ +getTubeStatFields(); +$groups = $console->getTubeStatGroups(); +$visible = $console->getTubeStatVisible(); +$sampleJobs = $console->getSampleJobs($tube); +$allStats = $console->getTubeStatValues($tube); + +$tubePauseSeconds = $settings->getTubePauseSeconds(); +if ($tubePauseSeconds === -1) { + $tubePauseSeconds = 3600; +} + +include('currentTubeJobsSummaryTable.php'); +include('currentTubeJobsActionsRow.php'); +include('currentTubeJobsShowcase.php'); diff --git a/lib/tpl/currentTubeJobsActionsRow.php b/lib/tpl/currentTubeJobsActionsRow.php new file mode 100644 index 0000000..870d380 --- /dev/null +++ b/lib/tpl/currentTubeJobsActionsRow.php @@ -0,0 +1,65 @@ +getSampleJobs($tube); +$buriedJobsCount = $allStats['current-jobs-buried']; + +$tubePauseSeconds = $settings->getTubePauseSeconds(); +if ($tubePauseSeconds === -1) { + $tubePauseSeconds = 3600; +} +?> +
+ Actions:  + Kick 1 job + +
+
+ + + + + +
+
+ + Kick all jobs + + + Pause tube Unpause tube +       +
+ Add job + + +
+
\ No newline at end of file diff --git a/lib/tpl/currentTubeJobsShowcase.php b/lib/tpl/currentTubeJobsShowcase.php new file mode 100644 index 0000000..13d4cee --- /dev/null +++ b/lib/tpl/currentTubeJobsShowcase.php @@ -0,0 +1,109 @@ +
+ $job): ?> +
+ +
+

Next job in "" state

+
+
+ + +
+
+ + + + + + + + + $value): ?> + + + + + + +
Stats: 
+ 0 ? 'days: ' . $days . '
' : ''; + echo $hours > 0 ? 'hours: ' . $hours . '
' : ''; + echo $minutes > 0 ? 'minutes: ' . $minutes . '
' : ''; + echo $seconds > 0 ? 'seconds: ' . $seconds : ''; + } else { + echo $value; + } + ?> +
+
+
+
+
+ Job data: +
+ +
+
+ Add to + samples + +
+ + +
+ Delete all jobs + Delete +
+
+ + +
+
+
+
+ + empty + + +
diff --git a/lib/tpl/currentTubeJobsSummaryTable.php b/lib/tpl/currentTubeJobsSummaryTable.php new file mode 100644 index 0000000..140405a --- /dev/null +++ b/lib/tpl/currentTubeJobsSummaryTable.php @@ -0,0 +1,56 @@ +getTubeStatFields(); +$visible = $console->getTubeStatVisible(); +?> +
+
+
+ + + + + $item) { + $markHidden = !in_array($key, $visible) ? ' class="hide"' : ''; + if (in_array($key, array('current-jobs-buried', 'current-jobs-delayed', 'current-jobs-ready'))) { + ?> + name="" title=""> + + name="" title=""> + + + + + + getTubeStatValues($tubeItem) ?> + + + $item): + $classes = array("td-$key"); + if (!in_array($key, $visible)) { + $classes[] = 'hide' ; + } + if (isset($tubeStats[$key]) && $tubeStats[$key] != '0') { + $classes[] = 'hasValue'; + } + $cssClass = '' ; + if (count($classes) > 0) { + $cssClass = ' class = "' . join(' ', $classes) . '"' ; + } + ?> + > + + + + +
name
+
+
+ +
\ No newline at end of file diff --git a/lib/tpl/currentTubeSearchResults.php b/lib/tpl/currentTubeSearchResults.php new file mode 100644 index 0000000..99e6440 --- /dev/null +++ b/lib/tpl/currentTubeSearchResults.php @@ -0,0 +1,74 @@ +getSearchResult(); +include('currentTubeJobsSummaryTable.php'); +?> +
+  Back to tube +
+ 0) { + unset($searchResults['total']); + ?> +
+
+
+ + + + + + + + + + + $jobList): ?> + + + + + + + + + + +
idstatedataaction
getId(); ?>getData()); ?> + +
+
+
+ First rows are displayed for each state. +
+
+
+ + +
+ No results found for in tube: + getServers(); -?> - - - - - - - - Beanstalk console - - - - - - - - - - - - - - - - - - - - -
- - - - -

Error

- - - - - - - -
- - -
- - - -

<< back - - - - - - - - - - -
- - - - - - - - - - - - +getServers(); +if ($server) { + $serverKey = array_search($server, $servers); + $serverLabel = is_numeric($serverKey) || empty($serverKey) ? $server : $serverKey; +} +$settings = new Settings(); +$jsDefaults = $settings->getAllDefaults(); +?> + + + + + + + + + + <?php if ($tube) echo $tube . ' - ' ?> + <?php echo !empty($serverLabel) ? $serverLabel : 'All servers' ?> - + Beanstalk console + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +

Error

+ + + + + +
+ +
+ + + +
+ + +
+ + + +

+ << back + + + + + + + + + + +
+ + + + + + + + isJobDataHighlightEnabled()) { + ?> + + + + + + + \ No newline at end of file diff --git a/lib/tpl/modalAddJob.php b/lib/tpl/modalAddJob.php index b72b4be..71225e6 100644 --- a/lib/tpl/modalAddJob.php +++ b/lib/tpl/modalAddJob.php @@ -8,8 +8,8 @@