commit 9a7a9e3593270eb7e979b03f6d3b52dab84bd665 Author: Simon Vieille Date: Mon Mar 2 21:22:57 2015 +0100 init diff --git a/README b/README new file mode 100644 index 0000000..1c24539 --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +CMS Install is a cli tool that helps you to download and install popular CMS. +It works on Linux/Unix systems. diff --git a/cms b/cms new file mode 100755 index 0000000..ea872fc --- /dev/null +++ b/cms @@ -0,0 +1,16 @@ +#!/usr/bin/env php +init(); +} +catch(Exception $e) { + Cli::printError('Fatal error', $e->getMessage()); + die(1); +} diff --git a/config/00_app.yml b/config/00_app.yml new file mode 100644 index 0000000..7847890 --- /dev/null +++ b/config/00_app.yml @@ -0,0 +1,42 @@ +app: + version: 0.1 + author: 'Simon Vieille' + contact: 'simon@deblan.fr / www.deblan.tv' + rules: + "version|v-s" : ~ + "list|l-s" : ~ + "help|h-s" : ~ + "install|i=s" : ~ + "to|d=s" : ~ + "create-dir|cd" : ~ + + configuration: + to: {hide: true} + create-dir: {hide: true} + version: + description: "Show CMS Installer version" + param: ~ + callback: + class: Information + method: version + + help: + description: "Show help" + param: '[command]' + callback: + class: Information + method: help + + list: + description: "Show CMS list" + param: '[cms]' + callback: + class: Information + method: list + + install: + param: 'name [--version version] [--to destination [--create-dir]]' + description: "Install a CMS" + callback: + class: Installation + method: install diff --git a/config/00_ressources.yml b/config/00_ressources.yml new file mode 100644 index 0000000..7b3ab0a --- /dev/null +++ b/config/00_ressources.yml @@ -0,0 +1,45 @@ +ressources: + cms: + Wordpress: + versions: + default: + callback: Wordpress + url: http://fr.wordpress.org/latest-fr_FR.zip + local: + callback: Wordpress + url: http://localhost/~simon/wp.zip + + Drupal: + versions: + default: + description: "Recommended release (version 7)" + url: http://ftp.drupal.org/files/projects/drupal-7.12.zip + v7.12: + description: "Recommended release (version 6)" + url: http://ftp.drupal.org/files/projects/drupal-7.12.zip + v6.25: + description: "Recommended release (version 6)" + url: http://ftp.drupal.org/files/projects/drupal-6.25.zip + v7dev: + description: "Development release (version 7)" + url: http://ftp.drupal.org/files/projects/drupal-7.x-dev.zip + v6dev: + description: "Development release (version 6)" + url: http://ftp.drupal.org/files/projects/drupal-6.x-dev.zip + + Joomla: + versions: + default: + url: http://aide.joomla.fr/telechargements/joomla-2-5-package-d-installation-et-patchs/joomla-2-5-4-edition-francophone/download + v2.5: + url: http://aide.joomla.fr/telechargements/joomla-2-5-package-d-installation-et-patchs/joomla-2-5-4-edition-francophone/download + v1.7: + url: http://aide.joomla.fr/telechargements/joomla-1-7-package-d-installation-et-patchs/joomla-1-7-5-edition-francophone/download + v1.5: + url: http://aide.joomla.fr/telechargements/joomla-1-5-packages-d-installation-et-patchs/joomla-1-5-26-stable-fr/download + + Pluxml: + versions: + default: + callback: Pluxml + url: http://telechargements.pluxml.org/download.php diff --git a/lib/Zend/Console/Getopt.php b/lib/Zend/Console/Getopt.php new file mode 100644 index 0000000..d603566 --- /dev/null +++ b/lib/Zend/Console/Getopt.php @@ -0,0 +1,970 @@ + self::MODE_ZEND, + self::CONFIG_DASHDASH => true, + self::CONFIG_IGNORECASE => false, + self::CONFIG_PARSEALL => true, + ); + + /** + * Stores the command-line arguments for the calling applicaion. + * + * @var array + */ + protected $_argv = array(); + + /** + * Stores the name of the calling applicaion. + * + * @var string + */ + protected $_progname = ''; + + /** + * Stores the list of legal options for this application. + * + * @var array + */ + protected $_rules = array(); + + /** + * Stores alternate spellings of legal options. + * + * @var array + */ + protected $_ruleMap = array(); + + /** + * Stores options given by the user in the current invocation + * of the application, as well as parameters given in options. + * + * @var array + */ + protected $_options = array(); + + /** + * Stores the command-line arguments other than options. + * + * @var array + */ + protected $_remainingArgs = array(); + + /** + * State of the options: parsed or not yet parsed? + * + * @var boolean + */ + protected $_parsed = false; + + /** + * The constructor takes one to three parameters. + * + * The first parameter is $rules, which may be a string for + * gnu-style format, or a structured array for Zend-style format. + * + * The second parameter is $argv, and it is optional. If not + * specified, $argv is inferred from the global argv. + * + * The third parameter is an array of configuration parameters + * to control the behavior of this instance of Getopt; it is optional. + * + * @param array $rules + * @param array $argv + * @param array $getoptConfig + * @return void + */ + public function __construct($rules, $argv = null, $getoptConfig = array()) + { + if (!isset($_SERVER['argv'])) { + require_once 'Zend/Console/Getopt/Exception.php'; + if (ini_get('register_argc_argv') == false) { + throw new Zend_Console_Getopt_Exception( + "argv is not available, because ini option 'register_argc_argv' is set Off" + ); + } else { + throw new Zend_Console_Getopt_Exception( + '$_SERVER["argv"] is not set, but Zend_Console_Getopt cannot work without this information.' + ); + } + } + + $this->_progname = $_SERVER['argv'][0]; + $this->setOptions($getoptConfig); + $this->addRules($rules); + if (!is_array($argv)) { + $argv = array_slice($_SERVER['argv'], 1); + } + if (isset($argv)) { + $this->addArguments((array)$argv); + } + } + + /** + * Return the state of the option seen on the command line of the + * current application invocation. This function returns true, or the + * parameter to the option, if any. If the option was not given, + * this function returns null. + * + * The magic __get method works in the context of naming the option + * as a virtual member of this class. + * + * @param string $key + * @return string + */ + public function __get($key) + { + return $this->getOption($key); + } + + /** + * Test whether a given option has been seen. + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + return isset($this->_options[$key]); + } + return false; + } + + /** + * Set the value for a given option. + * + * @param string $key + * @param string $value + * @return void + */ + public function __set($key, $value) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + $this->_options[$key] = $value; + } + } + + /** + * Return the current set of options and parameters seen as a string. + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Unset an option. + * + * @param string $key + * @return void + */ + public function __unset($key) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + unset($this->_options[$key]); + } + } + + /** + * Define additional command-line arguments. + * These are appended to those defined when the constructor was called. + * + * @param array $argv + * @throws Zend_Console_Getopt_Exception When not given an array as parameter + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function addArguments($argv) + { + if(!is_array($argv)) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Parameter #1 to addArguments should be an array"); + } + $this->_argv = array_merge($this->_argv, $argv); + $this->_parsed = false; + return $this; + } + + /** + * Define full set of command-line arguments. + * These replace any currently defined. + * + * @param array $argv + * @throws Zend_Console_Getopt_Exception When not given an array as parameter + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setArguments($argv) + { + if(!is_array($argv)) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Parameter #1 to setArguments should be an array"); + } + $this->_argv = $argv; + $this->_parsed = false; + return $this; + } + + /** + * Define multiple configuration options from an associative array. + * These are not program options, but properties to configure + * the behavior of Zend_Console_Getopt. + * + * @param array $getoptConfig + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setOptions($getoptConfig) + { + if (isset($getoptConfig)) { + foreach ($getoptConfig as $key => $value) { + $this->setOption($key, $value); + } + } + return $this; + } + + /** + * Define one configuration option as a key/value pair. + * These are not program options, but properties to configure + * the behavior of Zend_Console_Getopt. + * + * @param string $configKey + * @param string $configValue + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setOption($configKey, $configValue) + { + if ($configKey !== null) { + $this->_getoptConfig[$configKey] = $configValue; + } + return $this; + } + + /** + * Define additional option rules. + * These are appended to the rules defined when the constructor was called. + * + * @param array $rules + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function addRules($rules) + { + $ruleMode = $this->_getoptConfig['ruleMode']; + switch ($this->_getoptConfig['ruleMode']) { + case self::MODE_ZEND: + if (is_array($rules)) { + $this->_addRulesModeZend($rules); + break; + } + // intentional fallthrough + case self::MODE_GNU: + $this->_addRulesModeGnu($rules); + break; + default: + /** + * Call addRulesModeFoo() for ruleMode 'foo'. + * The developer should subclass Getopt and + * provide this method. + */ + $method = '_addRulesMode' . ucfirst($ruleMode); + $this->$method($rules); + } + $this->_parsed = false; + return $this; + } + + /** + * Return the current set of options and parameters seen as a string. + * + * @return string + */ + public function toString() + { + $this->parse(); + $s = array(); + foreach ($this->_options as $flag => $value) { + $s[] = $flag . '=' . ($value === true ? 'true' : $value); + } + return implode(' ', $s); + } + + /** + * Return the current set of options and parameters seen + * as an array of canonical options and parameters. + * + * Clusters have been expanded, and option aliases + * have been mapped to their primary option names. + * + * @return array + */ + public function toArray() + { + $this->parse(); + $s = array(); + foreach ($this->_options as $flag => $value) { + $s[] = $flag; + if ($value !== true) { + $s[] = $value; + } + } + return $s; + } + + /** + * Return the current set of options and parameters seen in Json format. + * + * @return string + */ + public function toJson() + { + $this->parse(); + $j = array(); + foreach ($this->_options as $flag => $value) { + $j['options'][] = array( + 'option' => array( + 'flag' => $flag, + 'parameter' => $value + ) + ); + } + + /** + * @see Zend_Json + */ + require_once 'Zend/Json.php'; + $json = Zend_Json::encode($j); + + return $json; + } + + /** + * Return the current set of options and parameters seen in XML format. + * + * @return string + */ + public function toXml() + { + $this->parse(); + $doc = new DomDocument('1.0', 'utf-8'); + $optionsNode = $doc->createElement('options'); + $doc->appendChild($optionsNode); + foreach ($this->_options as $flag => $value) { + $optionNode = $doc->createElement('option'); + $optionNode->setAttribute('flag', utf8_encode($flag)); + if ($value !== true) { + $optionNode->setAttribute('parameter', utf8_encode($value)); + } + $optionsNode->appendChild($optionNode); + } + $xml = $doc->saveXML(); + return $xml; + } + + /** + * Return a list of options that have been seen in the current argv. + * + * @return array + */ + public function getOptions() + { + $this->parse(); + return array_keys($this->_options); + } + + /** + * Return the state of the option seen on the command line of the + * current application invocation. + * + * This function returns true, or the parameter value to the option, if any. + * If the option was not given, this function returns false. + * + * @param string $flag + * @return mixed + */ + public function getOption($flag) + { + $this->parse(); + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + if (isset($this->_ruleMap[$flag])) { + $flag = $this->_ruleMap[$flag]; + if (isset($this->_options[$flag])) { + return $this->_options[$flag]; + } + } + return null; + } + + /** + * Return the arguments from the command-line following all options found. + * + * @return array + */ + public function getRemainingArgs() + { + $this->parse(); + return $this->_remainingArgs; + } + + /** + * Return a useful option reference, formatted for display in an + * error message. + * + * Note that this usage information is provided in most Exceptions + * generated by this class. + * + * @return string + */ + public function getUsageMessage() + { + $usage = "Usage: {$this->_progname} [ options ]\n"; + $maxLen = 20; + $lines = array(); + foreach ($this->_rules as $rule) { + $flags = array(); + if (is_array($rule['alias'])) { + foreach ($rule['alias'] as $flag) { + $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag; + } + } + $linepart['name'] = implode('|', $flags); + if (isset($rule['param']) && $rule['param'] != 'none') { + $linepart['name'] .= ' '; + switch ($rule['param']) { + case 'optional': + $linepart['name'] .= "[ <{$rule['paramType']}> ]"; + break; + case 'required': + $linepart['name'] .= "<{$rule['paramType']}>"; + break; + } + } + if (strlen($linepart['name']) > $maxLen) { + $maxLen = strlen($linepart['name']); + } + $linepart['help'] = ''; + if (isset($rule['help'])) { + $linepart['help'] .= $rule['help']; + } + $lines[] = $linepart; + } + foreach ($lines as $linepart) { + $usage .= sprintf("%s %s\n", + str_pad($linepart['name'], $maxLen), + $linepart['help']); + } + return $usage; + } + + /** + * Define aliases for options. + * + * The parameter $aliasMap is an associative array + * mapping option name (short or long) to an alias. + * + * @param array $aliasMap + * @throws Zend_Console_Getopt_Exception + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setAliases($aliasMap) + { + foreach ($aliasMap as $flag => $alias) + { + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + $alias = strtolower($alias); + } + if (!isset($this->_ruleMap[$flag])) { + continue; + } + $flag = $this->_ruleMap[$flag]; + if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) { + $o = (strlen($alias) == 1 ? '-' : '--') . $alias; + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"$o\" is being defined more than once."); + } + $this->_rules[$flag]['alias'][] = $alias; + $this->_ruleMap[$alias] = $flag; + } + return $this; + } + + /** + * Define help messages for options. + * + * The parameter $help_map is an associative array + * mapping option name (short or long) to the help string. + * + * @param array $helpMap + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setHelp($helpMap) + { + foreach ($helpMap as $flag => $help) + { + if (!isset($this->_ruleMap[$flag])) { + continue; + } + $flag = $this->_ruleMap[$flag]; + $this->_rules[$flag]['help'] = $help; + } + return $this; + } + + /** + * Parse command-line arguments and find both long and short + * options. + * + * Also find option parameters, and remaining arguments after + * all options have been parsed. + * + * @return Zend_Console_Getopt|null Provides a fluent interface + */ + public function parse() + { + if ($this->_parsed === true) { + return; + } + $argv = $this->_argv; + $this->_options = array(); + $this->_remainingArgs = array(); + while (count($argv) > 0) { + if ($argv[0] == '--') { + array_shift($argv); + if ($this->_getoptConfig[self::CONFIG_DASHDASH]) { + $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); + break; + } + } + if (substr($argv[0], 0, 2) == '--') { + $this->_parseLongOption($argv); + } else if (substr($argv[0], 0, 1) == '-' && ('-' != $argv[0] || count($argv) >1)) { + $this->_parseShortOptionCluster($argv); + } else if($this->_getoptConfig[self::CONFIG_PARSEALL]) { + $this->_remainingArgs[] = array_shift($argv); + } else { + /* + * We should put all other arguments in _remainingArgs and stop parsing + * since CONFIG_PARSEALL is false. + */ + $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); + break; + } + } + $this->_parsed = true; + return $this; + } + + /** + * Parse command-line arguments for a single long option. + * A long option is preceded by a double '--' character. + * Long options may not be clustered. + * + * @param mixed &$argv + * @return void + */ + protected function _parseLongOption(&$argv) + { + $optionWithParam = ltrim(array_shift($argv), '-'); + $l = explode('=', $optionWithParam, 2); + $flag = array_shift($l); + $param = array_shift($l); + if (isset($param)) { + array_unshift($argv, $param); + } + $this->_parseSingleOption($flag, $argv); + } + + /** + * Parse command-line arguments for short options. + * Short options are those preceded by a single '-' character. + * Short options may be clustered. + * + * @param mixed &$argv + * @return void + */ + protected function _parseShortOptionCluster(&$argv) + { + $flagCluster = ltrim(array_shift($argv), '-'); + foreach (str_split($flagCluster) as $flag) { + $this->_parseSingleOption($flag, $argv); + } + } + + /** + * Parse command-line arguments for a single option. + * + * @param string $flag + * @param mixed $argv + * @throws Zend_Console_Getopt_Exception + * @return void + */ + protected function _parseSingleOption($flag, &$argv) + { + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + if (!isset($this->_ruleMap[$flag])) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" is not recognized.", + $this->getUsageMessage()); + } + $realFlag = $this->_ruleMap[$flag]; + switch ($this->_rules[$realFlag]['param']) { + case 'required': + if (count($argv) > 0) { + $param = array_shift($argv); + $this->_checkParameterType($realFlag, $param); + } else { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires a parameter.", + $this->getUsageMessage()); + } + break; + case 'optional': + if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') { + $param = array_shift($argv); + $this->_checkParameterType($realFlag, $param); + } else { + $param = true; + } + break; + default: + $param = true; + } + $this->_options[$realFlag] = $param; + } + + /** + * Return true if the parameter is in a valid format for + * the option $flag. + * Throw an exception in most other cases. + * + * @param string $flag + * @param string $param + * @throws Zend_Console_Getopt_Exception + * @return bool + */ + protected function _checkParameterType($flag, $param) + { + $type = 'string'; + if (isset($this->_rules[$flag]['paramType'])) { + $type = $this->_rules[$flag]['paramType']; + } + switch ($type) { + case 'word': + if (preg_match('/\W/', $param)) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires a single-word parameter, but was given \"$param\".", + $this->getUsageMessage()); + } + break; + case 'integer': + if (preg_match('/\D/', $param)) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires an integer parameter, but was given \"$param\".", + $this->getUsageMessage()); + } + break; + case 'string': + default: + break; + } + return true; + } + + /** + * Define legal options using the gnu-style format. + * + * @param string $rules + * @return void + */ + protected function _addRulesModeGnu($rules) + { + $ruleArray = array(); + + /** + * Options may be single alphanumeric characters. + * Options may have a ':' which indicates a required string parameter. + * No long options or option aliases are supported in GNU style. + */ + preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray); + foreach ($ruleArray[1] as $rule) { + $r = array(); + $flag = substr($rule, 0, 1); + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + $r['alias'][] = $flag; + if (substr($rule, 1, 1) == ':') { + $r['param'] = 'required'; + $r['paramType'] = 'string'; + } else { + $r['param'] = 'none'; + } + $this->_rules[$flag] = $r; + $this->_ruleMap[$flag] = $flag; + } + } + + /** + * Define legal options using the Zend-style format. + * + * @param array $rules + * @throws Zend_Console_Getopt_Exception + * @return void + */ + protected function _addRulesModeZend($rules) + { + foreach ($rules as $ruleCode => $helpMessage) + { + // this may have to translate the long parm type if there + // are any complaints that =string will not work (even though that use + // case is not documented) + if (in_array(substr($ruleCode, -2, 1), array('-', '='))) { + $flagList = substr($ruleCode, 0, -2); + $delimiter = substr($ruleCode, -2, 1); + $paramType = substr($ruleCode, -1); + } else { + $flagList = $ruleCode; + $delimiter = $paramType = null; + } + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flagList = strtolower($flagList); + } + $flags = explode('|', $flagList); + $rule = array(); + $mainFlag = $flags[0]; + foreach ($flags as $flag) { + if (empty($flag)) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Blank flag not allowed in rule \"$ruleCode\"."); + } + if (strlen($flag) == 1) { + if (isset($this->_ruleMap[$flag])) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"-$flag\" is being defined more than once."); + } + $this->_ruleMap[$flag] = $mainFlag; + $rule['alias'][] = $flag; + } else { + if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) { + require_once 'Zend/Console/Getopt/Exception.php'; + throw new Zend_Console_Getopt_Exception( + "Option \"--$flag\" is being defined more than once."); + } + $this->_ruleMap[$flag] = $mainFlag; + $rule['alias'][] = $flag; + } + } + if (isset($delimiter)) { + switch ($delimiter) { + case self::PARAM_REQUIRED: + $rule['param'] = 'required'; + break; + case self::PARAM_OPTIONAL: + default: + $rule['param'] = 'optional'; + } + switch (substr($paramType, 0, 1)) { + case self::TYPE_WORD: + $rule['paramType'] = 'word'; + break; + case self::TYPE_INTEGER: + $rule['paramType'] = 'integer'; + break; + case self::TYPE_STRING: + default: + $rule['paramType'] = 'string'; + } + } else { + $rule['param'] = 'none'; + } + $rule['help'] = $helpMessage; + $this->_rules[$mainFlag] = $rule; + } + } + +} diff --git a/lib/Zend/Console/Getopt/Exception.php b/lib/Zend/Console/Getopt/Exception.php new file mode 100644 index 0000000..cabb406 --- /dev/null +++ b/lib/Zend/Console/Getopt/Exception.php @@ -0,0 +1,66 @@ +usage = $usage; + parent::__construct($message); + } + + /** + * Returns the usage + * + * @return string + */ + public function getUsageMessage() + { + return $this->usage; + } +} diff --git a/lib/Zend/Console_Getopt.class.php b/lib/Zend/Console_Getopt.class.php new file mode 100644 index 0000000..70da745 --- /dev/null +++ b/lib/Zend/Console_Getopt.class.php @@ -0,0 +1,7 @@ +_rules; + } +} diff --git a/lib/app/CmsInstallerApp.class.php b/lib/app/CmsInstallerApp.class.php new file mode 100644 index 0000000..602eaa6 --- /dev/null +++ b/lib/app/CmsInstallerApp.class.php @@ -0,0 +1,98 @@ +argv = $argv; + + $files = sfFinder::type('file')->name('*.yml')->in(ROOT.DIRECTORY_SEPARATOR.'config'); + + foreach($files as $file) { + $config = sfYaml::load($file); + + if($config) { + if(mySfYaml::getAll()) { + mySfYaml::merge($file); + } + else { + mySfYaml::load($file); + } + } + } + } + + public function init() { + $this->opts = new Console_Getopt(mySfYaml::get('app_rules')); + + if(count($this->argv) > 1) { + try { + $this->opts->parse(); + foreach($this->opts->getOptions() as $arg) { + $opt_config = mySfYaml::get('app_configuration_'.$arg); + + if(!isset($opt_config['callback'])) { + throw new CmsInstallerException($arg.' has not a callback configuration (callback parameter not found).'); + } + + if(!isset($opt_config['callback']['class'])) { + throw new CmsInstallerException($arg.' has not a callback configuration (class parameter not found).'); + } + + if(!isset($opt_config['callback']['method'])) { + throw new CmsInstallerException($arg.' has not a callback configuration (class method not found).'); + } + + $this->callback($opt_config['callback']['class'], $opt_config['callback']['method'], $this->get($arg)); + } + } + catch(Zend_Console_Getopt_Exception $e) { + CmsInstallerApp::showError('Invalid argument', 'Show help by using --help argument.'); + } + catch(CmsInstallerException $e) { + CmsInstallerApp::showError('Configuration error', $e->getMessage()); + } + } + } + + private function callback($class, $method, $value) { + $class.= 'Task'; + $method = 'execute'.ucfirst($method); + + if(!class_exists($class)) { + throw new CmsInstallerException($class.' class does not exist'); + } + + if(!method_exists($class, $method)) { + throw new CmsInstallerException($class.'::'.$method.' does not exist'); + } + + $callback = new $class($value, $this); + $callback->$method(); + } + + public function get($param) { + try { + return $this->opts->getOption($param); + } + catch(Zend_Console_Getopt_Exception $e) { + CmsInstallerApp::showError('Invalid argument', '"'.$param.'" is not a valid argument. Show help by using --help argument.'); + } + } + + public static function showError($title, $message) { + Cli::printError($title, $message); + exit(1); + } + + public function getArgv($n=null) { + return $n === null ? $this->argv : (isset($this->argv[$n]) ? $this->argv[$n] : null); + } + + public function getOpts() { + return $this->opts; + } +} diff --git a/lib/autoload/Autoload.class.php b/lib/autoload/Autoload.class.php new file mode 100644 index 0000000..df92e16 --- /dev/null +++ b/lib/autoload/Autoload.class.php @@ -0,0 +1,21 @@ +name('*.class.php')->in(ROOT.DIRECTORY_SEPARATOR.'lib'); + + foreach($files as $file) { + if(basename($file) == $class.'.class.php') { + require_once $file; + } + } + } +} + diff --git a/lib/cli/Cli.class.php b/lib/cli/Cli.class.php new file mode 100644 index 0000000..5126fce --- /dev/null +++ b/lib/cli/Cli.class.php @@ -0,0 +1,89 @@ + self::$width) { + $title.= "\n"; + } + else { + $title = str_pad($title, self::$width, ' ', STR_PAD_RIGHT); + } + $output.= $cliColors->getColoredString(' '.$title, $foreground, $background).' '; + } + + $output.= $message.($eol ? PHP_EOL : ''); + + fwrite($out, $output); + } + + public static function printError($title, $message) { + self::printMessage($title, $message, 'red', 'white', STDERR); + } + + public static function printNotice($title, $message) { + self::printMessage($title, $message, 'light_red', 'white'); + } + + public static function printInfo($title, $message) { + self::printMessage($title, $message, 'green', null); + } + + public static function printInfoNoEOL($title, $message) { + self::printMessage($title, $message, 'green', null, STDOUT, false); + } + + public static function printPrompt($title) { + self::printMessage($title, '', 'cyan', null, STDOUT, false); + } + + public static function printBlankLine() { + echo PHP_EOL; + } + + public static function prompt($title, $required=true, $default=null, $authorized_values=array()) { + $ask = true; + $promptValue = $default; + if(!empty($authorized_values)) { + $title.= ' ('.implode(', ', $authorized_values).')'; + } + + if($default !== null) { + $title.= ' ['.$default.']'; + } + + do { + self::printPrompt($title); + $promptValue = trim(fgets(STDIN)); + + if(!$required && empty($promptValue)) { + if(!empty($default)) { + $promptValue = $default; + } + $ask = false; + } + elseif($required && empty($promptValue)) { + if(!empty($default)) { + $promptValue = $default; + $ask = false; + } + else { + self::printNotice('> Required.', ''); + } + } + elseif(!empty($authorized_values) && !in_array($promptValue, $authorized_values)) { + self::printNotice('Oops', 'Forbidden value, please try again.'); + } + else { + $ask = false; + } + } while($ask); + + return $promptValue; + } +} diff --git a/lib/cli/CliColors.class.php b/lib/cli/CliColors.class.php new file mode 100644 index 0000000..a09f51c --- /dev/null +++ b/lib/cli/CliColors.class.php @@ -0,0 +1,76 @@ +foreground_colors['black'] = '0;30'; + $this->foreground_colors['dark_gray'] = '1;30'; + $this->foreground_colors['blue'] = '0;34'; + $this->foreground_colors['light_blue'] = '1;34'; + $this->foreground_colors['green'] = '0;32'; + $this->foreground_colors['light_green'] = '1;32'; + $this->foreground_colors['cyan'] = '0;36'; + $this->foreground_colors['light_cyan'] = '1;36'; + $this->foreground_colors['red'] = '0;31'; + $this->foreground_colors['light_red'] = '1;31'; + $this->foreground_colors['purple'] = '0;35'; + $this->foreground_colors['light_purple'] = '1;35'; + $this->foreground_colors['brown'] = '0;33'; + $this->foreground_colors['yellow'] = '1;33'; + $this->foreground_colors['light_gray'] = '0;37'; + $this->foreground_colors['white'] = '1;37'; + + $this->background_colors['black'] = '40'; + $this->background_colors['red'] = '41'; + $this->background_colors['green'] = '42'; + $this->background_colors['yellow'] = '43'; + $this->background_colors['blue'] = '44'; + $this->background_colors['magenta'] = '45'; + $this->background_colors['cyan'] = '46'; + $this->background_colors['light_gray'] = '47'; + } + + public static function getInstance() { + if(is_null(self::$_instance)) { + self::$_instance = new CliColors(); + } + return self::$_instance; + } + + // Returns colored string + public function getColoredString($string, $foreground_color = null, $background_color = null) { + $colored_string = ""; + + // Check if given foreground color found + if (isset($this->foreground_colors[$foreground_color])) { + $colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . "m"; + } + // Check if given background color found + if (isset($this->background_colors[$background_color])) { + $colored_string .= "\033[" . $this->background_colors[$background_color] . "m"; + } + + // Add string and end coloring + $colored_string .= $string . "\033[0m"; + + return $colored_string; + } + + // Returns all foreground color names + public function getForegroundColors() { + return array_keys($this->foreground_colors); + } + + // Returns all background color names + public function getBackgroundColors() { + return array_keys($this->background_colors); + } +} + diff --git a/lib/exception/CmsInstallerException.class.php b/lib/exception/CmsInstallerException.class.php new file mode 100644 index 0000000..70dbff2 --- /dev/null +++ b/lib/exception/CmsInstallerException.class.php @@ -0,0 +1,4 @@ + $value) { + if(!isset($global_config[$key])) { + $global_config[$key] = $value; + } + else { + if(is_array($value)) { + foreach($value as $vkey => $vvalue) { + if(!isset($global_config[$key][$vkey])) { + $global_config[$key][$vkey] = $vvalue; + } + else { + self::recursiveMerge($global_config[$key], $value); + } + } + } + else { + $global_config[$key] = $value; + } + } + } + } + + public static function getAll() { + return self::$global_config; + } + + public static function get($var) { + if(!self::$file_loaded) { + throw new Exception('Yaml file is not loaded yet, please see sfYaml::load method'); + } + + $road = self::$global_config; + + $parts = explode('_', $var); + + while(true) { + $shift = array_shift($parts); + + if(isset($road[$shift])) { + if(empty($parts)) { + return $road[$shift]; + } + else { + $road = $road[$shift]; + } + } + else { + return null; + } + } + } +} diff --git a/lib/sfYaml/sfYaml.class.php b/lib/sfYaml/sfYaml.class.php new file mode 100644 index 0000000..a45917e --- /dev/null +++ b/lib/sfYaml/sfYaml.class.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYaml offers convenience methods to load and dump YAML. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $ + */ +class sfYaml +{ + static protected + $spec = '1.2'; + + /** + * Sets the YAML specification version to use. + * + * @param string $version The YAML specification version + */ + static public function setSpecVersion($version) + { + if (!in_array($version, array('1.1', '1.2'))) + { + throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version)); + } + + self::$spec = $version; + } + + /** + * Gets the YAML specification version to use. + * + * @return string The YAML specification version + */ + static public function getSpecVersion() + { + return self::$spec; + } + + /** + * Loads YAML into a PHP array. + * + * The load method, when supplied with a YAML stream (string or file), + * will do its best to convert YAML in a file into a PHP array. + * + * Usage: + * + * $array = sfYaml::load('config.yml'); + * print_r($array); + * + * + * @param string $input Path of YAML file or string containing YAML + * + * @return array The YAML converted to a PHP array + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public static function load($input) + { + $file = ''; + + // if input is a file, process it + if (strpos($input, "\n") === false && is_file($input)) + { + $file = $input; + + ob_start(); + $retval = include($input); + $content = ob_get_clean(); + + // if an array is returned by the config file assume it's in plain php form else in YAML + $input = is_array($retval) ? $retval : $content; + } + + // if an array is returned by the config file assume it's in plain php form else in YAML + if (is_array($input)) + { + return $input; + } + + $yaml = new sfYamlParser(); + + try + { + $ret = $yaml->parse($input); + } + catch (Exception $e) + { + throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage())); + } + + return $ret; + } + + /** + * Dumps a PHP array to a YAML string. + * + * The dump method, when supplied with an array, will do its best + * to convert the array into friendly YAML. + * + * @param array $array PHP array + * @param integer $inline The level where you switch to inline YAML + * + * @return string A YAML string representing the original PHP array + */ + public static function dump($array, $inline = 2) + { + require_once dirname(__FILE__).'/sfYamlDumper.php'; + + $yaml = new sfYamlDumper(); + + return $yaml->dump($array, $inline); + } +} + +/** + * Wraps echo to automatically provide a newline. + * + * @param string $string The string to echo with new line + */ +function echoln($string) +{ + echo $string."\n"; +} diff --git a/lib/sfYaml/sfYamlDumper.class.php b/lib/sfYaml/sfYamlDumper.class.php new file mode 100644 index 0000000..130f236 --- /dev/null +++ b/lib/sfYaml/sfYamlDumper.class.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYamlDumper dumps PHP variables to YAML strings. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $ + */ +class sfYamlDumper +{ + /** + * Dumps a PHP value to YAML. + * + * @param mixed $input The PHP value + * @param integer $inline The level where you switch to inline YAML + * @param integer $indent The level o indentation indentation (used internally) + * + * @return string The YAML representation of the PHP value + */ + public function dump($input, $inline = 0, $indent = 0) + { + $output = ''; + $prefix = $indent ? str_repeat(' ', $indent) : ''; + + if ($inline <= 0 || !is_array($input) || empty($input)) + { + $output .= $prefix.sfYamlInline::dump($input); + } + else + { + $isAHash = array_keys($input) !== range(0, count($input) - 1); + + foreach ($input as $key => $value) + { + $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value); + + $output .= sprintf('%s%s%s%s', + $prefix, + $isAHash ? sfYamlInline::dump($key).':' : '-', + $willBeInlined ? ' ' : "\n", + $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2) + ).($willBeInlined ? "\n" : ''); + } + } + + return $output; + } +} diff --git a/lib/sfYaml/sfYamlInline.class.php b/lib/sfYaml/sfYamlInline.class.php new file mode 100644 index 0000000..3bb1868 --- /dev/null +++ b/lib/sfYaml/sfYamlInline.class.php @@ -0,0 +1,440 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfYamlInline implements a YAML parser/dumper for the YAML inline syntax. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $ + */ +class sfYamlInline +{ + const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')'; + + /** + * Convert a YAML string to a PHP array. + * + * @param string $value A YAML string + * + * @return array A PHP array representing the YAML string + */ + static public function load($value) + { + $value = trim($value); + + if (0 == strlen($value)) + { + return ''; + } + + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) + { + $mbEncoding = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } + + switch ($value[0]) + { + case '[': + $result = self::parseSequence($value); + break; + case '{': + $result = self::parseMapping($value); + break; + default: + $result = self::parseScalar($value); + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return $result; + } + + /** + * Dumps a given PHP variable to a YAML string. + * + * @param mixed $value The PHP variable to convert + * + * @return string The YAML string representing the PHP array + */ + static public function dump($value) + { + if ('1.1' === sfYaml::getSpecVersion()) + { + $trueValues = array('true', 'on', '+', 'yes', 'y'); + $falseValues = array('false', 'off', '-', 'no', 'n'); + } + else + { + $trueValues = array('true'); + $falseValues = array('false'); + } + + switch (true) + { + case is_resource($value): + throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.'); + case is_object($value): + return '!!php/object:'.serialize($value); + case is_array($value): + return self::dumpArray($value); + case null === $value: + return 'null'; + case true === $value: + return 'true'; + case false === $value: + return 'false'; + case ctype_digit($value): + return is_string($value) ? "'$value'" : (int) $value; + case is_numeric($value): + return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value); + case false !== strpos($value, "\n") || false !== strpos($value, "\r"): + return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value)); + case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ - ? | < > = ! % @ ` ]/x', $value): + return sprintf("'%s'", str_replace('\'', '\'\'', $value)); + case '' == $value: + return "''"; + case preg_match(self::getTimestampRegex(), $value): + return "'$value'"; + case in_array(strtolower($value), $trueValues): + return "'$value'"; + case in_array(strtolower($value), $falseValues): + return "'$value'"; + case in_array(strtolower($value), array('null', '~')): + return "'$value'"; + default: + return $value; + } + } + + /** + * Dumps a PHP array to a YAML string. + * + * @param array $value The PHP array to dump + * + * @return string The YAML string representing the PHP array + */ + static protected function dumpArray($value) + { + // array + $keys = array_keys($value); + if ( + (1 == count($keys) && '0' == $keys[0]) + || + (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2)) + { + $output = array(); + foreach ($value as $val) + { + $output[] = self::dump($val); + } + + return sprintf('[%s]', implode(', ', $output)); + } + + // mapping + $output = array(); + foreach ($value as $key => $val) + { + $output[] = sprintf('%s: %s', self::dump($key), self::dump($val)); + } + + return sprintf('{ %s }', implode(', ', $output)); + } + + /** + * Parses a scalar to a YAML string. + * + * @param scalar $scalar + * @param string $delimiters + * @param array $stringDelimiter + * @param integer $i + * @param boolean $evaluate + * + * @return string A YAML string + */ + static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true) + { + if (in_array($scalar[$i], $stringDelimiters)) + { + // quoted scalar + $output = self::parseQuotedScalar($scalar, $i); + } + else + { + // "normal" string + if (!$delimiters) + { + $output = substr($scalar, $i); + $i += strlen($output); + + // remove comments + if (false !== $strpos = strpos($output, ' #')) + { + $output = rtrim(substr($output, 0, $strpos)); + } + } + else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) + { + $output = $match[1]; + $i += strlen($output); + } + else + { + throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar)); + } + + $output = $evaluate ? self::evaluateScalar($output) : $output; + } + + return $output; + } + + /** + * Parses a quoted scalar to YAML. + * + * @param string $scalar + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseQuotedScalar($scalar, &$i) + { + if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) + { + throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i))); + } + + $output = substr($match[0], 1, strlen($match[0]) - 2); + + if ('"' == $scalar[$i]) + { + // evaluate the string + $output = str_replace(array('\\"', '\\n', '\\r'), array('"', "\n", "\r"), $output); + } + else + { + // unescape ' + $output = str_replace('\'\'', '\'', $output); + } + + $i += strlen($match[0]); + + return $output; + } + + /** + * Parses a sequence to a YAML string. + * + * @param string $sequence + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseSequence($sequence, &$i = 0) + { + $output = array(); + $len = strlen($sequence); + $i += 1; + + // [foo, bar, ...] + while ($i < $len) + { + switch ($sequence[$i]) + { + case '[': + // nested sequence + $output[] = self::parseSequence($sequence, $i); + break; + case '{': + // nested mapping + $output[] = self::parseMapping($sequence, $i); + break; + case ']': + return $output; + case ',': + case ' ': + break; + default: + $isQuoted = in_array($sequence[$i], array('"', "'")); + $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i); + + if (!$isQuoted && false !== strpos($value, ': ')) + { + // embedded mapping? + try + { + $value = self::parseMapping('{'.$value.'}'); + } + catch (InvalidArgumentException $e) + { + // no, it's not + } + } + + $output[] = $value; + + --$i; + } + + ++$i; + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence)); + } + + /** + * Parses a mapping to a YAML string. + * + * @param string $mapping + * @param integer $i + * + * @return string A YAML string + */ + static protected function parseMapping($mapping, &$i = 0) + { + $output = array(); + $len = strlen($mapping); + $i += 1; + + // {foo: bar, bar:foo, ...} + while ($i < $len) + { + switch ($mapping[$i]) + { + case ' ': + case ',': + ++$i; + continue 2; + case '}': + return $output; + } + + // key + $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + + // value + $done = false; + while ($i < $len) + { + switch ($mapping[$i]) + { + case '[': + // nested sequence + $output[$key] = self::parseSequence($mapping, $i); + $done = true; + break; + case '{': + // nested mapping + $output[$key] = self::parseMapping($mapping, $i); + $done = true; + break; + case ':': + case ' ': + break; + default: + $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i); + $done = true; + --$i; + } + + ++$i; + + if ($done) + { + continue 2; + } + } + } + + throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping)); + } + + /** + * Evaluates scalars and replaces magic values. + * + * @param string $scalar + * + * @return string A YAML string + */ + static protected function evaluateScalar($scalar) + { + $scalar = trim($scalar); + + if ('1.1' === sfYaml::getSpecVersion()) + { + $trueValues = array('true', 'on', '+', 'yes', 'y'); + $falseValues = array('false', 'off', '-', 'no', 'n'); + } + else + { + $trueValues = array('true'); + $falseValues = array('false'); + } + + switch (true) + { + case 'null' == strtolower($scalar): + case '' == $scalar: + case '~' == $scalar: + return null; + case 0 === strpos($scalar, '!str'): + return (string) substr($scalar, 5); + case 0 === strpos($scalar, '! '): + return intval(self::parseScalar(substr($scalar, 2))); + case 0 === strpos($scalar, '!!php/object:'): + return unserialize(substr($scalar, 13)); + case ctype_digit($scalar): + $raw = $scalar; + $cast = intval($scalar); + return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); + case in_array(strtolower($scalar), $trueValues): + return true; + case in_array(strtolower($scalar), $falseValues): + return false; + case is_numeric($scalar): + return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar); + case 0 == strcasecmp($scalar, '.inf'): + case 0 == strcasecmp($scalar, '.NaN'): + return -log(0); + case 0 == strcasecmp($scalar, '-.inf'): + return log(0); + case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): + return floatval(str_replace(',', '', $scalar)); + case preg_match(self::getTimestampRegex(), $scalar): + return strtotime($scalar); + default: + return (string) $scalar; + } + } + + static protected function getTimestampRegex() + { + return <<[0-9][0-9][0-9][0-9]) + -(?P[0-9][0-9]?) + -(?P[0-9][0-9]?) + (?:(?:[Tt]|[ \t]+) + (?P[0-9][0-9]?) + :(?P[0-9][0-9]) + :(?P[0-9][0-9]) + (?:\.(?P[0-9]*))? + (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) + (?::(?P[0-9][0-9]))?))?)? + $~x +EOF; + } +} diff --git a/lib/sfYaml/sfYamlParser.class.php b/lib/sfYaml/sfYamlParser.class.php new file mode 100644 index 0000000..820de59 --- /dev/null +++ b/lib/sfYaml/sfYamlParser.class.php @@ -0,0 +1,620 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!defined('PREG_BAD_UTF8_OFFSET_ERROR')) +{ + define('PREG_BAD_UTF8_OFFSET_ERROR', 5); +} + +/** + * sfYamlParser parses YAML strings to convert them to PHP arrays. + * + * @package symfony + * @subpackage yaml + * @author Fabien Potencier + * @version SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $ + */ +class sfYamlParser +{ + protected + $offset = 0, + $lines = array(), + $currentLineNb = -1, + $currentLine = '', + $refs = array(); + + /** + * Constructor + * + * @param integer $offset The offset of YAML document (used for line numbers in error messages) + */ + public function __construct($offset = 0) + { + $this->offset = $offset; + } + + /** + * Parses a YAML string to a PHP value. + * + * @param string $value A YAML string + * + * @return mixed A PHP value + * + * @throws InvalidArgumentException If the YAML is not valid + */ + public function parse($value) + { + $this->currentLineNb = -1; + $this->currentLine = ''; + $this->lines = explode("\n", $this->cleanup($value)); + + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) + { + $mbEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + } + + $data = array(); + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + continue; + } + + // tab? + if (preg_match('#^\t+#', $this->currentLine)) + { + throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + $isRef = $isInPlace = $isProcessed = false; + if (preg_match('#^\-((?P\s+)(?P.+?))?\s*$#u', $this->currentLine, $values)) + { + if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + // array + if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[] = $parser->parse($this->getNextEmbedBlock()); + } + else + { + if (isset($values['leadspaces']) + && ' ' == $values['leadspaces'] + && preg_match('#^(?P'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"\{].*?) *\:(\s+(?P.+?))?\s*$#u', $values['value'], $matches)) + { + // this is a compact notation element, add to next block and parse + $c = $this->getRealCurrentLineNb(); + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + + $block = $values['value']; + if (!$this->isNextLineIndented()) + { + $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2); + } + + $data[] = $parser->parse($block); + } + else + { + $data[] = $this->parseValue($values['value']); + } + } + } + else if (preg_match('#^(?P'.sfYamlInline::REGEX_QUOTED_STRING.'|[^ \'"].*?) *\:(\s+(?P.+?))?\s*$#u', $this->currentLine, $values)) + { + $key = sfYamlInline::parseScalar($values['key']); + + if ('<<' === $key) + { + if (isset($values['value']) && '*' === substr($values['value'], 0, 1)) + { + $isInPlace = substr($values['value'], 1); + if (!array_key_exists($isInPlace, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + if (isset($values['value']) && $values['value'] !== '') + { + $value = $values['value']; + } + else + { + $value = $this->getNextEmbedBlock(); + } + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $parsed = $parser->parse($value); + + $merged = array(); + if (!is_array($parsed)) + { + throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + else if (isset($parsed[0])) + { + // Numeric array, merge individual elements + foreach (array_reverse($parsed) as $parsedItem) + { + if (!is_array($parsedItem)) + { + throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem)); + } + $merged = array_merge($parsedItem, $merged); + } + } + else + { + // Associative array, merge + $merged = array_merge($merged, $parsed); + } + + $isProcessed = $merged; + } + } + else if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) + { + $isRef = $matches['ref']; + $values['value'] = $matches['value']; + } + + if ($isProcessed) + { + // Merge keys + $data = $isProcessed; + } + // hash + else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) + { + // if next line is less indented or equal, then it means that the current value is null + if ($this->isNextLineIndented()) + { + $data[$key] = null; + } + else + { + $c = $this->getRealCurrentLineNb() + 1; + $parser = new sfYamlParser($c); + $parser->refs =& $this->refs; + $data[$key] = $parser->parse($this->getNextEmbedBlock()); + } + } + else + { + if ($isInPlace) + { + $data = $this->refs[$isInPlace]; + } + else + { + $data[$key] = $this->parseValue($values['value']); + } + } + } + else + { + // 1-liner followed by newline + if (2 == count($this->lines) && empty($this->lines[1])) + { + $value = sfYamlInline::load($this->lines[0]); + if (is_array($value)) + { + $first = reset($value); + if ('*' === substr($first, 0, 1)) + { + $data = array(); + foreach ($value as $alias) + { + $data[] = $this->refs[substr($alias, 1)]; + } + $value = $data; + } + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return $value; + } + + switch (preg_last_error()) + { + case PREG_INTERNAL_ERROR: + $error = 'Internal PCRE error on line'; + break; + case PREG_BACKTRACK_LIMIT_ERROR: + $error = 'pcre.backtrack_limit reached on line'; + break; + case PREG_RECURSION_LIMIT_ERROR: + $error = 'pcre.recursion_limit reached on line'; + break; + case PREG_BAD_UTF8_ERROR: + $error = 'Malformed UTF-8 data on line'; + break; + case PREG_BAD_UTF8_OFFSET_ERROR: + $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point on line'; + break; + default: + $error = 'Unable to parse line'; + } + + throw new InvalidArgumentException(sprintf('%s %d (%s).', $error, $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + + if ($isRef) + { + $this->refs[$isRef] = end($data); + } + } + + if (isset($mbEncoding)) + { + mb_internal_encoding($mbEncoding); + } + + return empty($data) ? null : $data; + } + + /** + * Returns the current line number (takes the offset into account). + * + * @return integer The current line number + */ + protected function getRealCurrentLineNb() + { + return $this->currentLineNb + $this->offset; + } + + /** + * Returns the current line indentation. + * + * @return integer The current line indentation + */ + protected function getCurrentLineIndentation() + { + return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); + } + + /** + * Returns the next embed block of YAML. + * + * @param integer $indentation The indent level at which the block is to be read, or null for default + * + * @return string A YAML string + */ + protected function getNextEmbedBlock($indentation = null) + { + $this->moveToNextLine(); + + if (null === $indentation) + { + $newIndent = $this->getCurrentLineIndentation(); + + if (!$this->isCurrentLineEmpty() && 0 == $newIndent) + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + else + { + $newIndent = $indentation; + } + + $data = array(substr($this->currentLine, $newIndent)); + + while ($this->moveToNextLine()) + { + if ($this->isCurrentLineEmpty()) + { + if ($this->isCurrentLineBlank()) + { + $data[] = substr($this->currentLine, $newIndent); + } + + continue; + } + + $indent = $this->getCurrentLineIndentation(); + + if (preg_match('#^(?P *)$#', $this->currentLine, $match)) + { + // empty line + $data[] = $match['text']; + } + else if ($indent >= $newIndent) + { + $data[] = substr($this->currentLine, $newIndent); + } + else if (0 == $indent) + { + $this->moveToPreviousLine(); + + break; + } + else + { + throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine)); + } + } + + return implode("\n", $data); + } + + /** + * Moves the parser to the next line. + */ + protected function moveToNextLine() + { + if ($this->currentLineNb >= count($this->lines) - 1) + { + return false; + } + + $this->currentLine = $this->lines[++$this->currentLineNb]; + + return true; + } + + /** + * Moves the parser to the previous line. + */ + protected function moveToPreviousLine() + { + $this->currentLine = $this->lines[--$this->currentLineNb]; + } + + /** + * Parses a YAML value. + * + * @param string $value A YAML value + * + * @return mixed A PHP value + */ + protected function parseValue($value) + { + if ('*' === substr($value, 0, 1)) + { + if (false !== $pos = strpos($value, '#')) + { + $value = substr($value, 1, $pos - 2); + } + else + { + $value = substr($value, 1); + } + + if (!array_key_exists($value, $this->refs)) + { + throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine)); + } + return $this->refs[$value]; + } + + if (preg_match('/^(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?$/', $value, $matches)) + { + $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; + + return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers))); + } + else + { + return sfYamlInline::load($value); + } + } + + /** + * Parses a folded scalar. + * + * @param string $separator The separator that was used to begin this folded scalar (| or >) + * @param string $indicator The indicator that was used to begin this folded scalar (+ or -) + * @param integer $indentation The indentation that was used to begin this folded scalar + * + * @return string The text value + */ + protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0) + { + $separator = '|' == $separator ? "\n" : ' '; + $text = ''; + + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineBlank()) + { + $text .= "\n"; + + $notEOF = $this->moveToNextLine(); + } + + if (!$notEOF) + { + return ''; + } + + if (!preg_match('#^(?P'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P.*)$#u', $this->currentLine, $matches)) + { + $this->moveToPreviousLine(); + + return ''; + } + + $textIndent = $matches['indent']; + $previousIndent = 0; + + $text .= $matches['text'].$separator; + while ($this->currentLineNb + 1 < count($this->lines)) + { + $this->moveToNextLine(); + + if (preg_match('#^(?P {'.strlen($textIndent).',})(?P.+)$#u', $this->currentLine, $matches)) + { + if (' ' == $separator && $previousIndent != $matches['indent']) + { + $text = substr($text, 0, -1)."\n"; + } + $previousIndent = $matches['indent']; + + $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator); + } + else if (preg_match('#^(?P *)$#', $this->currentLine, $matches)) + { + $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n"; + } + else + { + $this->moveToPreviousLine(); + + break; + } + } + + if (' ' == $separator) + { + // replace last separator by a newline + $text = preg_replace('/ (\n*)$/', "\n$1", $text); + } + + switch ($indicator) + { + case '': + $text = preg_replace('#\n+$#s', "\n", $text); + break; + case '+': + break; + case '-': + $text = preg_replace('#\n+$#s', '', $text); + break; + } + + return $text; + } + + /** + * Returns true if the next line is indented. + * + * @return Boolean Returns true if the next line is indented, false otherwise + */ + protected function isNextLineIndented() + { + $currentIndentation = $this->getCurrentLineIndentation(); + $notEOF = $this->moveToNextLine(); + + while ($notEOF && $this->isCurrentLineEmpty()) + { + $notEOF = $this->moveToNextLine(); + } + + if (false === $notEOF) + { + return false; + } + + $ret = false; + if ($this->getCurrentLineIndentation() <= $currentIndentation) + { + $ret = true; + } + + $this->moveToPreviousLine(); + + return $ret; + } + + /** + * Returns true if the current line is blank or if it is a comment line. + * + * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise + */ + protected function isCurrentLineEmpty() + { + return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); + } + + /** + * Returns true if the current line is blank. + * + * @return Boolean Returns true if the current line is blank, false otherwise + */ + protected function isCurrentLineBlank() + { + return '' == trim($this->currentLine, ' '); + } + + /** + * Returns true if the current line is a comment line. + * + * @return Boolean Returns true if the current line is a comment line, false otherwise + */ + protected function isCurrentLineComment() + { + //checking explicitly the first char of the trim is faster than loops or strpos + $ltrimmedLine = ltrim($this->currentLine, ' '); + return $ltrimmedLine[0] === '#'; + } + + /** + * Cleanups a YAML string to be parsed. + * + * @param string $value The input YAML string + * + * @return string A cleaned up YAML string + */ + protected function cleanup($value) + { + $value = str_replace(array("\r\n", "\r"), "\n", $value); + + if (!preg_match("#\n$#", $value)) + { + $value .= "\n"; + } + + // strip YAML header + $count = 0; + $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count); + $this->offset += $count; + + // remove leading comments + $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count); + if ($count == 1) + { + // items have been removed, update the offset + $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); + $value = $trimmedValue; + } + + // remove start of the document marker (---) + $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count); + if ($count == 1) + { + // items have been removed, update the offset + $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); + $value = $trimmedValue; + + // remove end of the document marker (...) + $value = preg_replace('#\.\.\.\s*$#s', '', $value); + } + + return $value; + } +} diff --git a/lib/task/BasicTask.class.php b/lib/task/BasicTask.class.php new file mode 100644 index 0000000..270f726 --- /dev/null +++ b/lib/task/BasicTask.class.php @@ -0,0 +1,19 @@ +value = $value; + $this->cmsInstallerApp = $app; + } + + protected function getValue() { + return $this->value; + } + + protected function getCmsInstallerApp() { + return $this->cmsInstallerApp; + } +} diff --git a/lib/task/InformationTask.class.php b/lib/task/InformationTask.class.php new file mode 100644 index 0000000..06bc1a3 --- /dev/null +++ b/lib/task/InformationTask.class.php @@ -0,0 +1,52 @@ +getCmsInstallerApp()->getOpts()->getRules() as $opt => $rule) { + if(!mySfYaml::get('app_configuration_'.$opt.'_hide')) { + if(($this->getValue() !== true && $this->getValue() == $opt) || $this->getValue() === true) { + $name = '--'.$opt.(isset($rule['alias'][1]) ? ',-'.$rule['alias'][1] : ''); + $param = mySfYaml::get('app_configuration_'.$opt.'_param'); + $description = mySfYaml::get('app_configuration_'.$opt.'_description'); + + Cli::printNotice($opt, ''); + Cli::printInfo(' Command', $name); + if(!empty($param)) { + Cli::printInfo(' Param', $param); + } + Cli::printInfo(' Description', $description); + Cli::printBlankLine(); + } + } + } + } + + public function executeVersion() { + Cli::printNotice('Cms Installer', ''); + Cli::printBlankLine(); + Cli::printInfo('Version', mySfYaml::get('app_version')); + Cli::printInfo('Author', mySfYaml::get('app_author')); + Cli::printInfo('Contact', mySfYaml::get('app_contact')); + } + + public function executeList() { + $cmss = mySfYaml::get('ressources_cms'); + + if(is_array($cmss)) { + foreach($cmss as $cms_name => $cms_info) { + if(($this->getValue() !== true && $this->getValue() == $cms_name) || $this->getValue() === true) { + Cli::printNotice($cms_name, ''); + if(isset($cms_info['versions']) && is_array($cms_info['versions'])) { + foreach($cms_info['versions'] as $version => $info) { + $description = !empty($info['description']) ? $info['description'] : 'No description.'; + Cli::printInfo(' '.$version, $description); + Cli::printInfo(' ', $info['url']); + Cli::printInfo(' ', $this->getCmsInstallerApp()->getArgv(0).' --install "'.$cms_name.'" --version "'.$version.'"'); + Cli::printBlankLine(); + } + } + } + } + } + } +} diff --git a/lib/task/InstallationTask.class.php b/lib/task/InstallationTask.class.php new file mode 100644 index 0000000..786658b --- /dev/null +++ b/lib/task/InstallationTask.class.php @@ -0,0 +1,137 @@ +arg_cms = $this->getValue(); + $this->arg_version = ($v = $this->getCmsInstallerApp()->get('version')) ? $v : 'default'; + + $this->cms_configuration = mySfYaml::get('ressources_cms_'.$this->arg_cms); + $this->cms_version = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version); + $this->cms_version_url = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version.'_url'); + $this->cms_callback = mySfYaml::get('ressources_cms_'.$this->arg_cms.'_versions_'.$this->arg_version.'_callback'); + $this->destination = ($dir = $this->getCmsInstallerApp()->get('to')) ? $dir : '.'; + + try { + if($this->getCmsInstallerApp()->get('create-dir') && !is_dir($this->destination)) { + if(!@mkdir($this->destination)) { + throw new CmsInstallerException('The directory "'.$this->destination.'" can not be created'); + } + } + + if(!$this->cms_configuration) { + throw new CmsInstallerException($this->arg_cms.' is not a valid cms. Show cms list by using --list argument.'); + } + + if(!$this->cms_version) { + throw new CmsInstallerException($this->arg_version.' is not a valid cms version for '.$this->arg_cms.'. Show cms list by using --list argument.'); + } + + if(!$this->cms_version_url) { + throw new CmsInstallerException($this->arg_cms.' (version '.$this->arg_version.') has not valid configuration (url not found). Show cms list by using --list argument.'); + } + + Cli::printNotice('CMS: ', $this->arg_cms); + Cli::printNotice('Version: ', $this->arg_version); + Cli::printNotice('Download from: ', $this->cms_version_url); + Cli::printBlankLine(); + + $this->tempName = $this->getTempName(); + $this->download(); + echo PHP_EOL; + $this->unpack(); + $this->clearFile(); + + if($this->cms_callback) { + $callback = $this->cms_callback.'InstallationTask'; + + if(!class_exists($callback)) { + throw new CmsInstallerException($this->arg_cms.' (version '.$this->arg_version.') has not valid configuration (callback "'.$callback.'" class not found).'); + } + Cli::printBlankLine(); + $callback = new $callback($this->destination, $this->arg_version); + $callback->execute(); + } + } + catch(CmsInstallerException $e) { + Cli::printError('Error', $e->getMessage()); + exit(1); + } + + exit(0); + } + + public static function progressBar($curl, $fd) { + if($curl) { + $purcent = round(100*$fd/$curl, 2); + $progress = str_pad($purcent.'%', 5, ' ', STR_PAD_RIGHT); + echo "\r"; + Cli::printInfoNoEOL('Progress', $progress); + } + } + + public function download() { + Cli::printInfo('Download started', 'Please wait...'); + + $fileopen = fopen($this->tempName, 'w'); + $curl = curl_init($this->cms_version_url); + + curl_setopt($curl, CURLOPT_FILE, $fileopen); + curl_setopt($curl, CURLOPT_NOPROGRESS, false); + curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, 'InstallationTask::progressBar'); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + + if(curl_errno($curl)) { + fclose($fileopen); + $this->clearFile(); + throw new CmsInstallerException('Download has failed.'); + } + + curl_exec($curl); + curl_close($curl); + fclose($fileopen); + } + + public function unpack() { + Cli::printInfo('Unpack', 'Please wait...'); + + $finfo = new finfo(FILEINFO_MIME); + $ftype = explode(';', $finfo->file($this->tempName)); + $type = $ftype[0]; + + if(!is_dir($this->destination)) { + throw new CmsInstallerException('Extract destination does not exist (extract to '.$this->destination.').'); + } + else { + if(!is_writable($this->destination)) { + throw new CmsInstallerException('Extract destination is not writable (extract to '.$this->destination.').'); + } + } + + if(in_array($type, array('application/zip', 'application/x-zip', 'application/x-zip-compressed'))) { + $zip = new ZipArchive(); + if(!$zip->open($this->tempName)) { + throw new CmsInstallerException('ZipArchive can not open package.'); + } + + $zip->extractTo($this->destination); + $zip->close(); + Cli::printInfo('Extact to', $this->destination); + } + elseif(in_array($type, array('application/x-tar', 'application/x-gtar', ))) { + throw new CmsInstallerException('Sorry but tar files are not supported yet...'); + } + else { + throw new CmsInstallerException('The archive is either in unknown format or damaged.'); + } + } + + public function getTempName() { + return $this->arg_cms.'-'.mt_rand(); + } + + public function clearFile() { + if(is_file($this->tempName)) { + unlink($this->tempName); + } + } +} diff --git a/lib/task/installationTask/BasicInstallationTask.class.php b/lib/task/installationTask/BasicInstallationTask.class.php new file mode 100644 index 0000000..cb5aa47 --- /dev/null +++ b/lib/task/installationTask/BasicInstallationTask.class.php @@ -0,0 +1,13 @@ +destination = getcwd().DIRECTORY_SEPARATOR.$destination; + $this->version = $version; + } + + abstract public function execute(); +} diff --git a/lib/task/installationTask/PluxmlInstallationTask.class.php b/lib/task/installationTask/PluxmlInstallationTask.class.php new file mode 100644 index 0000000..4b3d24b --- /dev/null +++ b/lib/task/installationTask/PluxmlInstallationTask.class.php @@ -0,0 +1,185 @@ + Cli::prompt('Your name:', true), + 'login' => Cli::prompt('Username:', true), + 'pwd' => Cli::prompt('Password:', true, StringUtil::genPassword()), + ); + + + define('PLX_ROOT', $this->destination.DIRECTORY_SEPARATOR.'pluxml'.DIRECTORY_SEPARATOR); + define('PLX_CORE', PLX_ROOT.'core'.DIRECTORY_SEPARATOR); + define('PLX_CONF', PLX_ROOT.'data'.DIRECTORY_SEPARATOR.'configuration'.DIRECTORY_SEPARATOR.'parametres.xml'); + + require_once PLX_ROOT.DIRECTORY_SEPARATOR.'config.php'; + + $lang = DEFAULT_LANG; + + loadLang(PLX_CORE.'lang/'.$lang.DIRECTORY_SEPARATOR.'install.php'); + loadLang(PLX_CORE.'lang/'.$lang.DIRECTORY_SEPARATOR.'core.php'); + + require_once PLX_CORE.'lib'.DIRECTORY_SEPARATOR.'class.plx.glob.php'; + require_once PLX_CORE.'lib'.DIRECTORY_SEPARATOR.'class.plx.utils.php'; + + if(!is_dir($dir=$this->destination.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'images')) { + @mkdir($dir, 0755); + } + if(!is_dir($dir=$this->destination.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'documents')) { + @mkdir($dir, 0755); + } + + $version = trim(file_get_contents(PLX_ROOT.'version')); + + $config = array('title'=>'PluXml', + 'description'=>plxUtils::strRevCheck(L_SITE_DESCRIPTION), + 'meta_description'=>'', + 'meta_keywords'=>'', + 'racine'=>$racine, + 'delta'=>'+00:00', + 'allow_com'=>1, + 'mod_com'=>0, + 'mod_art'=>0, + 'capcha'=>1, + 'style'=>'defaut', + 'clef'=>plxUtils::charAleatoire(15), + 'bypage'=>5, + 'bypage_archives'=>5, + 'bypage_admin'=>10, + 'bypage_admin_coms'=>10, + 'bypage_feed'=>8, + 'tri'=>'desc', + 'tri_coms'=>'asc', + 'images_l'=>800, + 'images_h'=>600, + 'miniatures_l'=>200, + 'miniatures_h'=>100, + 'images'=>'data/images/', + 'documents'=>'data/documents/', + 'racine_articles'=>'data/articles/', + 'racine_commentaires'=>'data/commentaires/', + 'racine_statiques'=>'data/statiques/', + 'racine_themes'=>'themes/', + 'racine_plugins'=>'plugins/', + 'statiques'=>'data/configuration/statiques.xml', + 'categories'=>'data/configuration/categories.xml', + 'users'=>'data/configuration/users.xml', + 'tags'=>'data/configuration/tags.xml', + 'plugins'=>'data/configuration/plugins.xml', + 'homestatic'=>'', + 'urlrewriting'=>0, + 'gzip'=>0, + 'feed_chapo'=>0, + 'feed_footer'=>'', + 'version'=>$version, + 'default_lang'=>$lang, + 'userfolders'=>0, + ); + + $this->install($content, $config); + + Cli::printNotice('Finished', 'You can now use the Pluxml.'); + } + + private function install($content, $config) { + +# Création du fichier de configuration + $xml = ''."\n"; + $xml .= ''."\n"; + foreach($config as $k=>$v) { + if(is_numeric($v)) + $xml .= "\t".$v."\n"; + else + $xml .= "\t\n"; + } + $xml .= ''; + plxUtils::write($xml,PLX_CONF); + +# Création du fichier des utilisateurs + $salt = plxUtils::charAleatoire(10); + $xml = ''."\n"; + $xml .= "\n"; + $xml .= "\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\t".''."\n"; + $xml .= "\t\n"; + $xml .= ""; + plxUtils::write($xml,PLX_ROOT.$config['users']); + +# Création du fichier des categories + $xml = ''."\n"; + $xml .= ''."\n"; + $xml .= "\t".''."\n"; + $xml .= ''; + plxUtils::write($xml,PLX_ROOT.$config['categories']); + +# Création du fichier des pages statiques + $xml = ''."\n"; + $xml .= ''."\n"; + $xml .= "\t".''."\n"; + $xml .= ''; + plxUtils::write($xml,PLX_ROOT.$config['statiques']); + $cs = '

'; + plxUtils::write($cs,PLX_ROOT.$config['racine_statiques'].'001.'.L_DEFAULT_STATIC_URL.'.php'); + +# Création du premier article + $xml = ''."\n"; + $xml .= ' + <![CDATA['.plxUtils::strRevCheck(L_DEFAULT_ARTICLE_TITLE).']]> + 1 + + + + + + '.plxUtils::strRevCheck(L_DEFAULT_ARTICLE_CONTENT).'

]]> +
+ + + + + + + + + + + + +
'; + plxUtils::write($xml,PLX_ROOT.$config['racine_articles'].'0001.001.001.'.@date('YmdHi').'.'.L_DEFAULT_ARTICLE_URL.'.xml'); + +# Création du fichier des tags servant de cache + $xml = ''."\n"; + $xml .= ''."\n"; + $xml .= "\t".'
'."\n"; + $xml .= '
'; + plxUtils::write($xml,PLX_ROOT.$config['tags']); + +# Création du fichier des plugins + $xml = ''."\n"; + $xml .= ''."\n"; + $xml .= ''; + plxUtils::write($xml,PLX_ROOT.$config['plugins']); + +# Création du premier commentaire + $xml = ''."\n"; + $xml .= ' + + normal + 127.0.0.1 + + + + '; + plxUtils::write($xml,PLX_ROOT.$config['racine_commentaires'].'0001.'.@date('U').'-1.xml'); + } +} diff --git a/lib/task/installationTask/WordpressInstallationTask.class.php b/lib/task/installationTask/WordpressInstallationTask.class.php new file mode 100644 index 0000000..62e0d53 --- /dev/null +++ b/lib/task/installationTask/WordpressInstallationTask.class.php @@ -0,0 +1,467 @@ +db_name = null; + $this->db_username = 'root'; + $this->db_password = ''; + $this->db_hostname = 'localhost'; + + do { + $config_ok = true; + + $this->db_name = Cli::prompt('Database name:', true, $this->db_name); + $this->db_username = Cli::prompt('Database username:', true, $this->db_username); + $this->db_password = Cli::prompt('Database password:', false, $this->db_password); + $this->db_hostname = Cli::prompt('Database hostname:', true, $this->db_hostname); + $this->db_charset = Cli::prompt('Database charset:', true, 'utf8'); + $this->db_prefix = Cli::prompt('Database table prefix:', true, 'wp_'); + Cli::printBlankLine(); + + $config_ok = true; + + if(!@mysql_connect($this->db_hostname, $this->db_username, $this->db_password)) { + $config_ok = false; + Cli::printNotice('Database login has failed:', mysql_error()); + } + if(!@mysql_select_db($this->db_name)) { + $config_ok = false; + Cli::printNotice('Select database has failed:', mysql_error()); + } + + if($config_ok) { + Cli::printBlankLine(); + } + } + while(!$config_ok); + + Cli::printNotice('Security configuration', ''); + $this->auth_key = Cli::prompt('Auth key (unique):', true, StringUtil::genPassword()); + $this->secure_auth_key = Cli::prompt('Secure auth key (unique):', true, StringUtil::genPassword()); + $this->logged_in_key = Cli::prompt('Logged in key (unique):', true, StringUtil::genPassword()); + $this->nonce_key = Cli::prompt('Nonce key (unique):', true, StringUtil::genPassword()); + $this->secure_auth_salt = Cli::prompt('Secure auth salt (unique):', true, StringUtil::genPassword()); + $this->auth_salt = Cli::prompt('Auth salt (unique):', true, StringUtil::genPassword()); + $this->logged_in_salt = Cli::prompt('Logged in salt (unique):', true, StringUtil::genPassword()); + $this->nonce_salt = Cli::prompt('Nonce in salt (unique):', true, StringUtil::genPassword()); + Cli::printBlankLine(); + + Cli::printNotice('Wordpress configuration', ''); + $this->site_url = Cli::prompt('Blog url (with http://)', true, 'http://localhost/wordpress/'); + $this->wplang = Cli::prompt('Lang', true, 'fr_FR'); + $this->wptitle = Cli::prompt('Blog title', true, 'My new blog'); + Cli::printBlankLine(); + + Cli::printNotice('Admin user configuration', ''); + $this->username = Cli::prompt('Admin username:', true, 'admin'); + $this->password = Cli::prompt('Admin password:', true, StringUtil::genPassword()); + + $this->email = null; + do { + if($this->email !== null) { + Cli::printNotice(' > Please enter en valid email.', ''); + } + $this->email = Cli::prompt('Admin email:', true); + } + while(!filter_var($this->email, FILTER_VALIDATE_EMAIL)); + + Cli::printBlankLine(); + + try { + $this->setDatabaseConfigurationFile(); + $this->initDatabase(); + } + catch(CmsInstallerException $e) { + Cli::printError('Error during configuration', $e->getMessage()); + } + } + + private function setDatabaseConfigurationFile() { + $configSample = $this->destination.DIRECTORY_SEPARATOR.'wordpress'.DIRECTORY_SEPARATOR.'wp-config-sample.php'; + $configFile = $this->destination.DIRECTORY_SEPARATOR.'wordpress'.DIRECTORY_SEPARATOR.'wp-config.php'; + + if(!file_exists($configSample)) { + throw new CmsInstallerException('Database configuration sample file does not exist.'); + } + + +$config = <<db_name'); +define('DB_USER', '$this->db_username'); +define('DB_PASSWORD', '$this->db_password'); +define('DB_HOST', '$this->db_hostname'); +define('DB_CHARSET', '$this->db_charset'); +define('DB_COLLATE', ''); +define('AUTH_KEY', '$this->auth_key'); +define('SECURE_AUTH_KEY', '$this->secure_auth_key'); +define('LOGGED_IN_KEY', '$this->logged_in_key'); +define('NONCE_KEY', '$this->nonce_key'); +define('AUTH_SALT', '$this->auth_salt'); +define('SECURE_AUTH_SALT', '$this->secure_auth_salt'); +define('LOGGED_IN_SALT', '$this->logged_in_salt'); +define('NONCE_SALT', '$this->nonce_salt'); +\$table_prefix = '$this->db_prefix'; +define('WPLANG', '$this->wplang'); +define('WP_DEBUG', false); +if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); +require_once(ABSPATH . 'wp-settings.php'); +EOF; + + if(!@file_put_contents($configFile, $config)) { + throw new CmsInstallerException('Error while creation database configuration file.'); + } + + Cli::printNotice('Database configuration file', 'done.'); + } + + private function initDatabase() { + $sql = array( +"SET NAMES ".$this->db_charset, +"CREATE TABLE IF NOT EXISTS `wp_commentmeta` ( + `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `comment_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `meta_key` varchar(255) DEFAULT NULL, + `meta_value` longtext, + PRIMARY KEY (`meta_id`), + KEY `comment_id` (`comment_id`), + KEY `meta_key` (`meta_key`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1", + +"CREATE TABLE IF NOT EXISTS `wp_comments` ( + `comment_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `comment_post_ID` bigint(20) unsigned NOT NULL DEFAULT '0', + `comment_author` tinytext NOT NULL, + `comment_author_email` varchar(100) NOT NULL DEFAULT '', + `comment_author_url` varchar(200) NOT NULL DEFAULT '', + `comment_author_IP` varchar(100) NOT NULL DEFAULT '', + `comment_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `comment_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `comment_content` text NOT NULL, + `comment_karma` int(11) NOT NULL DEFAULT '0', + `comment_approved` varchar(20) NOT NULL DEFAULT '1', + `comment_agent` varchar(255) NOT NULL DEFAULT '', + `comment_type` varchar(20) NOT NULL DEFAULT '', + `comment_parent` bigint(20) unsigned NOT NULL DEFAULT '0', + `user_id` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`comment_ID`), + KEY `comment_approved` (`comment_approved`), + KEY `comment_post_ID` (`comment_post_ID`), + KEY `comment_approved_date_gmt` (`comment_approved`,`comment_date_gmt`), + KEY `comment_date_gmt` (`comment_date_gmt`), + KEY `comment_parent` (`comment_parent`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2", + +"INSERT INTO `wp_comments` (`comment_ID`, `comment_post_ID`, `comment_author`, `comment_author_email`, `comment_author_url`, `comment_author_IP`, `comment_date`, `comment_date_gmt`, `comment_content`, `comment_karma`, `comment_approved`, `comment_agent`, `comment_type`, `comment_parent`, `user_id`) VALUES +(1, 1, 'Monsieur WordPress', '', 'http://wordpress.org/', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Bonjour, ceci est un commentaire.
Pour supprimer un commentaire, connectez-vous, et affichez les commentaires de cet article. Vous pourrez alors les modifier ou les supprimer.', 0, '1', '', '', 0, 0)", + +"CREATE TABLE IF NOT EXISTS `wp_links` ( + `link_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `link_url` varchar(255) NOT NULL DEFAULT '', + `link_name` varchar(255) NOT NULL DEFAULT '', + `link_image` varchar(255) NOT NULL DEFAULT '', + `link_target` varchar(25) NOT NULL DEFAULT '', + `link_description` varchar(255) NOT NULL DEFAULT '', + `link_visible` varchar(20) NOT NULL DEFAULT 'Y', + `link_owner` bigint(20) unsigned NOT NULL DEFAULT '1', + `link_rating` int(11) NOT NULL DEFAULT '0', + `link_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `link_rel` varchar(255) NOT NULL DEFAULT '', + `link_notes` mediumtext NOT NULL, + `link_rss` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`link_id`), + KEY `link_visible` (`link_visible`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=8", + +"INSERT INTO `wp_links` (`link_id`, `link_url`, `link_name`, `link_image`, `link_target`, `link_description`, `link_visible`, `link_owner`, `link_rating`, `link_updated`, `link_rel`, `link_notes`, `link_rss`) VALUES +(1, 'http://codex.wordpress.org/', 'Documentation', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''), +(2, 'http://wordpress.org/news/', 'WordPress Blog', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', 'http://wordpress.org/news/feed/'), +(3, 'http://wordpress.org/extend/ideas/', 'Suggest Ideas', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''), +(4, 'http://wordpress.org/support/', 'Support Forum', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''), +(5, 'http://wordpress.org/extend/plugins/', 'Plugins', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''), +(6, 'http://wordpress.org/extend/themes/', 'Themes', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', ''), +(7, 'http://planet.wordpress.org/', 'WordPress Planet', '', '', '', 'Y', 1, 0, '0000-00-00 00:00:00', '', '', '')", + +"CREATE TABLE IF NOT EXISTS `wp_options` ( + `option_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `blog_id` int(11) NOT NULL DEFAULT '0', + `option_name` varchar(64) NOT NULL DEFAULT '', + `option_value` longtext NOT NULL, + `autoload` varchar(20) NOT NULL DEFAULT 'yes', + PRIMARY KEY (`option_id`), + UNIQUE KEY `option_name` (`option_name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=106", + +"INSERT INTO `wp_options` (`option_id`, `blog_id`, `option_name`, `option_value`, `autoload`) VALUES +(1, 0, '_site_transient_timeout_theme_roots', '1333949458', 'yes'), +(2, 0, '_site_transient_theme_roots', 'a:2:{s:12:\"twentyeleven\";s:7:\"/themes\";s:9:\"twentyten\";s:7:\"/themes\";}', 'yes'), +(3, 0, 'siteurl', '".addslashes($this->site_url)."', 'yes'), +(4, 0, 'blogname', '".addslashes($this->wptitle)."', 'yes'), +(5, 0, 'blogdescription', 'Un site utilisant WordPress', 'yes'), +(6, 0, 'users_can_register', '0', 'yes'), +(7, 0, 'admin_email', '".$this->email."', 'yes'), +(8, 0, 'start_of_week', '1', 'yes'), +(9, 0, 'use_balanceTags', '0', 'yes'), +(10, 0, 'use_smilies', '1', 'yes'), +(11, 0, 'require_name_email', '1', 'yes'), +(12, 0, 'comments_notify', '1', 'yes'), +(13, 0, 'posts_per_rss', '10', 'yes'), +(14, 0, 'rss_use_excerpt', '0', 'yes'), +(15, 0, 'mailserver_url', 'mail.example.com', 'yes'), +(16, 0, 'mailserver_login', 'login@example.com', 'yes'), +(17, 0, 'mailserver_pass', 'password', 'yes'), +(18, 0, 'mailserver_port', '110', 'yes'), +(19, 0, 'default_category', '1', 'yes'), +(20, 0, 'default_comment_status', 'open', 'yes'), +(21, 0, 'default_ping_status', 'open', 'yes'), +(22, 0, 'default_pingback_flag', '1', 'yes'), +(23, 0, 'default_post_edit_rows', '20', 'yes'), +(24, 0, 'posts_per_page', '10', 'yes'), +(25, 0, 'date_format', 'j F Y', 'yes'), +(26, 0, 'time_format', 'G \\h i \\m\\i\\n', 'yes'), +(27, 0, 'links_updated_date_format', 'j F Y, G \\h i \\m\\i\\n', 'yes'), +(28, 0, 'links_recently_updated_prepend', '', 'yes'), +(29, 0, 'links_recently_updated_append', '', 'yes'), +(30, 0, 'links_recently_updated_time', '120', 'yes'), +(31, 0, 'comment_moderation', '0', 'yes'), +(32, 0, 'moderation_notify', '1', 'yes'), +(33, 0, 'permalink_structure', '', 'yes'), +(34, 0, 'gzipcompression', '0', 'yes'), +(35, 0, 'hack_file', '0', 'yes'), +(36, 0, 'blog_charset', 'UTF-8', 'yes'), +(37, 0, 'moderation_keys', '', 'no'), +(38, 0, 'active_plugins', 'a:0:{}', 'yes'), +(39, 0, 'home', '".addslashes($this->site_url)."', 'yes'), +(40, 0, 'category_base', '', 'yes'), +(41, 0, 'ping_sites', 'http://rpc.pingomatic.com/', 'yes'), +(42, 0, 'advanced_edit', '0', 'yes'), +(43, 0, 'comment_max_links', '2', 'yes'), +(44, 0, 'gmt_offset', '0', 'yes'), +(45, 0, 'default_email_category', '1', 'yes'), +(46, 0, 'recently_edited', '', 'no'), +(47, 0, 'template', 'twentyeleven', 'yes'), +(48, 0, 'stylesheet', 'twentyeleven', 'yes'), +(49, 0, 'comment_whitelist', '1', 'yes'), +(50, 0, 'blacklist_keys', '', 'no'), +(51, 0, 'comment_registration', '0', 'yes'), +(52, 0, 'rss_language', 'en', 'yes'), +(53, 0, 'html_type', 'text/html', 'yes'), +(54, 0, 'use_trackback', '0', 'yes'), +(55, 0, 'default_role', 'subscriber', 'yes'), +(56, 0, 'db_version', '19470', 'yes'), +(57, 0, 'uploads_use_yearmonth_folders', '1', 'yes'), +(58, 0, 'upload_path', '', 'yes'), +(59, 0, 'blog_public', '1', 'yes'), +(60, 0, 'default_link_category', '2', 'yes'), +(61, 0, 'show_on_front', 'posts', 'yes'), +(62, 0, 'tag_base', '', 'yes'), +(63, 0, 'show_avatars', '1', 'yes'), +(64, 0, 'avatar_rating', 'G', 'yes'), +(65, 0, 'upload_url_path', '', 'yes'), +(66, 0, 'thumbnail_size_w', '150', 'yes'), +(67, 0, 'thumbnail_size_h', '150', 'yes'), +(68, 0, 'thumbnail_crop', '1', 'yes'), +(69, 0, 'medium_size_w', '300', 'yes'), +(70, 0, 'medium_size_h', '300', 'yes'), +(71, 0, 'avatar_default', 'mystery', 'yes'), +(72, 0, 'enable_app', '0', 'yes'), +(73, 0, 'enable_xmlrpc', '0', 'yes'), +(74, 0, 'large_size_w', '1024', 'yes'), +(75, 0, 'large_size_h', '1024', 'yes'), +(76, 0, 'image_default_link_type', 'file', 'yes'), +(77, 0, 'image_default_size', '', 'yes'), +(78, 0, 'image_default_align', '', 'yes'), +(79, 0, 'close_comments_for_old_posts', '0', 'y/es'), +(80, 0, 'close_comments_days_old', '14', 'yes'), +(81, 0, 'thread_comments', '1', 'yes'), +(82, 0, 'thread_comments_depth', '5', 'yes'), +(83, 0, 'page_comments', '0', 'yes'), +(84, 0, 'comments_per_page', '50', 'yes'), +(85, 0, 'default_comments_page', 'newest', 'yes'), +(86, 0, 'comment_order', 'asc', 'yes'), +(87, 0, 'sticky_posts', 'a:0:{}', 'yes'), +(88, 0, 'widget_categories', 'a:2:{i:2;a:4:{s:5:\"title\";s:0:\"\";s:5:\"count\";i:0;s:12:\"hierarchical\";i:0;s:8:\"dropdown\";i:0;}s:12:\"_multiwidget\";i:1;}', 'yes'), +(89, 0, 'widget_text', 'a:0:{}', 'yes'), +(90, 0, 'widget_rss', 'a:0:{}', 'yes'), +(91, 0, 'timezone_string', '', 'yes'), +(92, 0, 'embed_autourls', '1', 'yes'), +(93, 0, 'embed_size_w', '', 'yes'), +(94, 0, 'embed_size_h', '600', 'yes'), +(95, 0, 'page_for_posts', '0', 'yes'), +(96, 0, 'page_on_front', '0', 'yes'), +(97, 0, 'default_post_format', '0', 'yes'), +(98, 0, 'initial_db_version', '19470', 'yes'), +(99, 0, 'wp_user_roles', 'a:5:{s:13:\"administrator\";a:2:{s:4:\"name\";s:13:\"Administrator\";s:12:\"capabilities\";a:62:{s:13:\"switch_themes\";b:1;s:11:\"edit_themes\";b:1;s:16:\"activate_plugins\";b:1;s:12:\"edit_plugins\";b:1;s:10:\"edit_users\";b:1;s:10:\"edit_files\";b:1;s:14:\"manage_options\";b:1;s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:6:\"import\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:8:\"level_10\";b:1;s:7:\"level_9\";b:1;s:7:\"level_8\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:12:\"delete_users\";b:1;s:12:\"create_users\";b:1;s:17:\"unfiltered_upload\";b:1;s:14:\"edit_dashboard\";b:1;s:14:\"update_plugins\";b:1;s:14:\"delete_plugins\";b:1;s:15:\"install_plugins\";b:1;s:13:\"update_themes\";b:1;s:14:\"install_themes\";b:1;s:11:\"update_core\";b:1;s:10:\"list_users\";b:1;s:12:\"remove_users\";b:1;s:9:\"add_users\";b:1;s:13:\"promote_users\";b:1;s:18:\"edit_theme_options\";b:1;s:13:\"delete_themes\";b:1;s:6:\"export\";b:1;}}s:6:\"editor\";a:2:{s:4:\"name\";s:6:\"Editor\";s:12:\"capabilities\";a:34:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;}}s:6:\"author\";a:2:{s:4:\"name\";s:6:\"Author\";s:12:\"capabilities\";a:10:{s:12:\"upload_files\";b:1;s:10:\"edit_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;s:22:\"delete_published_posts\";b:1;}}s:11:\"contributor\";a:2:{s:4:\"name\";s:11:\"Contributor\";s:12:\"capabilities\";a:5:{s:10:\"edit_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;}}s:10:\"subscriber\";a:2:{s:4:\"name\";s:10:\"Subscriber\";s:12:\"capabilities\";a:2:{s:4:\"read\";b:1;s:7:\"level_0\";b:1;}}}', 'yes'), +(100, 0, 'widget_search', 'a:2:{i:2;a:1:{s:5:\"title\";s:0:\"\";}s:12:\"_multiwidget\";i:1;}', 'yes'), +(101, 0, 'widget_recent-posts', 'a:2:{i:2;a:2:{s:5:\"title\";s:0:\"\";s:6:\"number\";i:5;}s:12:\"_multiwidget\";i:1;}', 'yes'), +(102, 0, 'widget_recent-comments', 'a:2:{i:2;a:2:{s:5:\"title\";s:0:\"\";s:6:\"number\";i:5;}s:12:\"_multiwidget\";i:1;}', 'yes'), +(103, 0, 'widget_archives', 'a:2:{i:2;a:3:{s:5:\"title\";s:0:\"\";s:5:\"count\";i:0;s:8:\"dropdown\";i:0;}s:12:\"_multiwidget\";i:1;}', 'yes'), +(104, 0, 'widget_meta', 'a:2:{i:2;a:1:{s:5:\"title\";s:0:\"\";}s:12:\"_multiwidget\";i:1;}', 'yes'), +(105, 0, 'sidebars_widgets', 'a:7:{s:19:\"wp_inactive_widgets\";a:0:{}s:9:\"sidebar-1\";a:6:{i:0;s:8:\"search-2\";i:1;s:14:\"recent-posts-2\";i:2;s:17:\"recent-comments-2\";i:3;s:10:\"archives-2\";i:4;s:12:\"categories-2\";i:5;s:6:\"meta-2\";}s:9:\"sidebar-2\";a:0:{}s:9:\"sidebar-3\";a:0:{}s:9:\"sidebar-4\";a:0:{}s:9:\"sidebar-5\";a:0:{}s:13:\"array_version\";i:3;}', 'yes')", + +"CREATE TABLE IF NOT EXISTS `wp_postmeta` ( + `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `post_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `meta_key` varchar(255) DEFAULT NULL, + `meta_value` longtext, + PRIMARY KEY (`meta_id`), + KEY `post_id` (`post_id`), + KEY `meta_key` (`meta_key`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2", + +"INSERT INTO `wp_postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES +(1, 2, '_wp_page_template', 'default')", + +"CREATE TABLE IF NOT EXISTS `wp_posts` ( + `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `post_author` bigint(20) unsigned NOT NULL DEFAULT '0', + `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `post_content` longtext NOT NULL, + `post_title` text NOT NULL, + `post_excerpt` text NOT NULL, + `post_status` varchar(20) NOT NULL DEFAULT 'publish', + `comment_status` varchar(20) NOT NULL DEFAULT 'open', + `ping_status` varchar(20) NOT NULL DEFAULT 'open', + `post_password` varchar(20) NOT NULL DEFAULT '', + `post_name` varchar(200) NOT NULL DEFAULT '', + `to_ping` text NOT NULL, + `pinged` text NOT NULL, + `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `post_content_filtered` text NOT NULL, + `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0', + `guid` varchar(255) NOT NULL DEFAULT '', + `menu_order` int(11) NOT NULL DEFAULT '0', + `post_type` varchar(20) NOT NULL DEFAULT 'post', + `post_mime_type` varchar(100) NOT NULL DEFAULT '', + `comment_count` bigint(20) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`), + KEY `post_name` (`post_name`), + KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`), + KEY `post_parent` (`post_parent`), + KEY `post_author` (`post_author`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3", + +"INSERT INTO `wp_posts` (`ID`, `post_author`, `post_date`, `post_date_gmt`, `post_content`, `post_title`, `post_excerpt`, `post_status`, `comment_status`, `ping_status`, `post_password`, `post_name`, `to_ping`, `pinged`, `post_modified`, `post_modified_gmt`, `post_content_filtered`, `post_parent`, `guid`, `menu_order`, `post_type`, `post_mime_type`, `comment_count`) VALUES +(1, 1, '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Bienvenue dans WordPress. Ceci est votre premier article. Modifiez-le ou supprimez-le, puis lancez-vous !', 'Bonjour tout le monde !', '', 'publish', 'open', 'open', '', 'bonjour-tout-le-monde', '', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', '', 0, '".addslashes($this->site_url)."/?p=1', 0, 'post', '', 1), +(2, 1, '2012-04-09 03:30:58', '2012-04-09 03:30:58', 'Voici un exemple de page. Elle est différente d''un article de blog, en cela qu''elle restera à la même place, et s''affichera dans le menu de navigation de votre site (en fonction de votre thème). La plupart des gens commencent par écrire une page « À Propos » qui les présente aux visiteurs potentiels du site. Vous pourriez y écrire quelque chose de ce tenant :\n\n
Bonjour ! Je suis un mécanicien qui aspire à devenir un acteur, et ceci est mon blog. J''habite à Bordeaux, j''ai un super chien baptisé Russell, et j''aime la vodka-ananas (ainsi que perdre mon temps à regarder la pluie tomber).
\n\n...ou bien quelque chose comme ça :\n\n
La société 123 Machin Truc a été créée en 1971, et n''a cessé de proposer au public des machins-trucs de qualité depuis cette année. Située à Saint-Remy-en-Bouzemont-Saint-Genest-et-Isson, 123 Machin Truc emploie 2 000 personnes, et fabrique toutes sortes de bidules super pour la communauté bouzemontoise.
\n\nEtant donné que vous êtes un nouvel utilisateur de WordPress, vous devriez vous rendre sur votre site_url)."/wp-admin/\">tableau de bord pour effacer la présente page, et créer de nouvelles pages avec votre propre contenu. Amusez-vous bien !', 'Page d’exemple', '', 'publish', 'open', 'open', '', 'page-d-exemple', '', '', '2012-04-09 03:30:58', '2012-04-09 03:30:58', '', 0, 'http://".addslashes($this->site_url)."/?page_id=2', 0, 'page', '', 0)", + +"CREATE TABLE IF NOT EXISTS `wp_terms` ( + `term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(200) NOT NULL DEFAULT '', + `slug` varchar(200) NOT NULL DEFAULT '', + `term_group` bigint(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`term_id`), + UNIQUE KEY `slug` (`slug`), + KEY `name` (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3", + +"INSERT INTO `wp_terms` (`term_id`, `name`, `slug`, `term_group`) VALUES +(1, 'Non classé', 'non-classe', 0), +(2, 'Liens', 'liens', 0)", + +"CREATE TABLE IF NOT EXISTS `wp_term_relationships` ( + `object_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `term_order` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`object_id`,`term_taxonomy_id`), + KEY `term_taxonomy_id` (`term_taxonomy_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8", + +"INSERT INTO `wp_term_relationships` (`object_id`, `term_taxonomy_id`, `term_order`) VALUES +(1, 2, 0), +(2, 2, 0), +(3, 2, 0), +(4, 2, 0), +(5, 2, 0), +(6, 2, 0), +(7, 2, 0), +(1, 1, 0)", + +"CREATE TABLE IF NOT EXISTS `wp_term_taxonomy` ( + `term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `term_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `taxonomy` varchar(32) NOT NULL DEFAULT '', + `description` longtext NOT NULL, + `parent` bigint(20) unsigned NOT NULL DEFAULT '0', + `count` bigint(20) NOT NULL DEFAULT '0', + PRIMARY KEY (`term_taxonomy_id`), + UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`), + KEY `taxonomy` (`taxonomy`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3", + +"INSERT INTO `wp_term_taxonomy` (`term_taxonomy_id`, `term_id`, `taxonomy`, `description`, `parent`, `count`) VALUES +(1, 1, 'category', '', 0, 1), +(2, 2, 'link_category', '', 0, 7)", + +"CREATE TABLE IF NOT EXISTS `wp_usermeta` ( + `umeta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `user_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `meta_key` varchar(255) DEFAULT NULL, + `meta_value` longtext, + PRIMARY KEY (`umeta_id`), + KEY `user_id` (`user_id`), + KEY `meta_key` (`meta_key`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=14", + +"INSERT INTO `wp_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALUES +(1, 1, 'first_name', ''), +(2, 1, 'last_name', ''), +(3, 1, 'nickname', 'admin'), +(4, 1, 'description', ''), +(5, 1, 'rich_editing', 'true'), +(6, 1, 'comment_shortcuts', 'false'), +(7, 1, 'admin_color', 'fresh'), +(8, 1, 'use_ssl', '0'), +(9, 1, 'show_admin_bar_front', 'true'), +(10, 1, 'wp_capabilities', 'a:1:{s:13:\"administrator\";s:1:\"1\";}'), +(11, 1, 'wp_user_level', '10'), +(12, 1, 'dismissed_wp_pointers', 'wp330_toolbar,wp330_media_uploader,wp330_saving_widgets'), +(13, 1, 'show_welcome_panel', '1')", + +"CREATE TABLE IF NOT EXISTS `wp_users` ( + `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `user_login` varchar(60) NOT NULL DEFAULT '', + `user_pass` varchar(64) NOT NULL DEFAULT '', + `user_nicename` varchar(50) NOT NULL DEFAULT '', + `user_email` varchar(100) NOT NULL DEFAULT '', + `user_url` varchar(100) NOT NULL DEFAULT '', + `user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `user_activation_key` varchar(60) NOT NULL DEFAULT '', + `user_status` int(11) NOT NULL DEFAULT '0', + `display_name` varchar(250) NOT NULL DEFAULT '', + PRIMARY KEY (`ID`), + KEY `user_login_key` (`user_login`), + KEY `user_nicename` (`user_nicename`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2", + +"INSERT INTO `wp_users` (`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) VALUES +(1, '".addslashes($this->username)."', '".md5($this->password)."', '".addslashes($this->username)."', '".addslashes($this->email)."', '', NOW(), '', 0, '".addslashes($this->username)."')" +); + + if(!@mysql_connect($this->db_hostname, $this->db_username, $this->db_password)) { + Cli::printNotice('Database login has failed:', mysql_error()); + exit(1); + } + elseif(!@mysql_select_db($this->db_name)) { + Cli::printNotice('Select database has failed:', mysql_error()); + exit(1); + } + + foreach($sql as $req) { + @mysql_query($req) or (Cli::printNotice('SQL error', mysql_error())); + } + + Cli::printBlankLine(); + Cli::printNotice('Finished', 'You can now use the wordpress.'); + } +} diff --git a/lib/util/StringUtil.class.php b/lib/util/StringUtil.class.php new file mode 100644 index 0000000..d5dfd4d --- /dev/null +++ b/lib/util/StringUtil.class.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + +/** + * + * Allow to build rules to find files and directories. + * + * All rules may be invoked several times, except for ->in() method. + * Some rules are cumulative (->name() for example) whereas others are destructive + * (most recent value is used, ->maxdepth() method for example). + * + * All methods return the current sfFinder object to allow easy chaining: + * + * $files = sfFinder::type('file')->name('*.php')->in(.); + * + * Interface loosely based on perl File::Find::Rule module. + * + * @package symfony + * @subpackage util + * @author Fabien Potencier + * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $ + */ +class sfFinder +{ + protected $type = 'file'; + protected $names = array(); + protected $prunes = array(); + protected $discards = array(); + protected $execs = array(); + protected $mindepth = 0; + protected $sizes = array(); + protected $maxdepth = 1000000; + protected $relative = false; + protected $follow_link = false; + protected $sort = false; + protected $ignore_version_control = true; + + /** + * Sets maximum directory depth. + * + * Finder will descend at most $level levels of directories below the starting point. + * + * @param int $level + * @return sfFinder current sfFinder object + */ + public function maxdepth($level) + { + $this->maxdepth = $level; + + return $this; + } + + /** + * Sets minimum directory depth. + * + * Finder will start applying tests at level $level. + * + * @param int $level + * @return sfFinder current sfFinder object + */ + public function mindepth($level) + { + $this->mindepth = $level; + + return $this; + } + + public function get_type() + { + return $this->type; + } + + /** + * Sets the type of elements to returns. + * + * @param string $name directory or file or any (for both file and directory) + * @return sfFinder new sfFinder object + */ + public static function type($name) + { + $finder = new self(); + return $finder->setType($name); + } + /** + * Sets the type of elements to returns. + * + * @param string $name directory or file or any (for both file and directory) + * @return sfFinder Current object + */ + public function setType($name) + { + $name = strtolower($name); + + if (substr($name, 0, 3) === 'dir') + { + $this->type = 'directory'; + + return $this; + } + if ($name === 'any') + { + $this->type = 'any'; + + return $this; + } + + $this->type = 'file'; + + return $this; + } + + /* + * glob, patterns (must be //) or strings + */ + protected function to_regex($str) + { + if (preg_match('/^(!)?([^a-zA-Z0-9\\\\]).+?\\2[ims]?$/', $str)) + { + return $str; + } + + return sfGlobToRegex::glob_to_regex($str); + } + + protected function args_to_array($arg_list, $not = false) + { + $list = array(); + $nbArgList = count($arg_list); + for ($i = 0; $i < $nbArgList; $i++) + { + if (is_array($arg_list[$i])) + { + foreach ($arg_list[$i] as $arg) + { + $list[] = array($not, $this->to_regex($arg)); + } + } + else + { + $list[] = array($not, $this->to_regex($arg_list[$i])); + } + } + + return $list; + } + + /** + * Adds rules that files must match. + * + * You can use patterns (delimited with / sign), globs or simple strings. + * + * $finder->name('*.php') + * $finder->name('/\.php$/') // same as above + * $finder->name('test.php') + * + * @param list a list of patterns, globs or strings + * @return sfFinder Current object + */ + public function name() + { + $args = func_get_args(); + $this->names = array_merge($this->names, $this->args_to_array($args)); + + return $this; + } + + /** + * Adds rules that files must not match. + * + * @see ->name() + * @param list a list of patterns, globs or strings + * @return sfFinder Current object + */ + public function not_name() + { + $args = func_get_args(); + $this->names = array_merge($this->names, $this->args_to_array($args, true)); + + return $this; + } + + /** + * Adds tests for file sizes. + * + * $finder->size('> 10K'); + * $finder->size('<= 1Ki'); + * $finder->size(4); + * + * @param list a list of comparison strings + * @return sfFinder Current object + */ + public function size() + { + $args = func_get_args(); + $numargs = count($args); + for ($i = 0; $i < $numargs; $i++) + { + $this->sizes[] = new sfNumberCompare($args[$i]); + } + + return $this; + } + + /** + * Traverses no further. + * + * @param list a list of patterns, globs to match + * @return sfFinder Current object + */ + public function prune() + { + $args = func_get_args(); + $this->prunes = array_merge($this->prunes, $this->args_to_array($args)); + + return $this; + } + + /** + * Discards elements that matches. + * + * @param list a list of patterns, globs to match + * @return sfFinder Current object + */ + public function discard() + { + $args = func_get_args(); + $this->discards = array_merge($this->discards, $this->args_to_array($args)); + + return $this; + } + + /** + * Ignores version control directories. + * + * Currently supports Subversion, CVS, DARCS, Gnu Arch, Monotone, Bazaar-NG, GIT, Mercurial + * + * @param bool $ignore falase when version control directories shall be included (default is true) + * + * @return sfFinder Current object + */ + public function ignore_version_control($ignore = true) + { + $this->ignore_version_control = $ignore; + + return $this; + } + + /** + * Returns files and directories ordered by name + * + * @return sfFinder Current object + */ + public function sort_by_name() + { + $this->sort = 'name'; + + return $this; + } + + /** + * Returns files and directories ordered by type (directories before files), then by name + * + * @return sfFinder Current object + */ + public function sort_by_type() + { + $this->sort = 'type'; + + return $this; + } + + /** + * Executes function or method for each element. + * + * Element match if functino or method returns true. + * + * $finder->exec('myfunction'); + * $finder->exec(array($object, 'mymethod')); + * + * @param mixed function or method to call + * @return sfFinder Current object + */ + public function exec() + { + $args = func_get_args(); + $numargs = count($args); + for ($i = 0; $i < $numargs; $i++) + { + if (is_array($args[$i]) && !method_exists($args[$i][0], $args[$i][1])) + { + throw new sfException(sprintf('method "%s" does not exist for object "%s".', $args[$i][1], $args[$i][0])); + } + if (!is_array($args[$i]) && !function_exists($args[$i])) + { + throw new sfException(sprintf('function "%s" does not exist.', $args[$i])); + } + + $this->execs[] = $args[$i]; + } + + return $this; + } + + /** + * Returns relative paths for all files and directories. + * + * @return sfFinder Current object + */ + public function relative() + { + $this->relative = true; + + return $this; + } + + /** + * Symlink following. + * + * @return sfFinder Current object + */ + public function follow_link() + { + $this->follow_link = true; + + return $this; + } + + /** + * Searches files and directories which match defined rules. + * + * @return array list of files and directories + */ + public function in() + { + $files = array(); + $here_dir = getcwd(); + + $finder = clone $this; + + if ($this->ignore_version_control) + { + $ignores = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'); + + $finder->discard($ignores)->prune($ignores); + } + + // first argument is an array? + $numargs = func_num_args(); + $arg_list = func_get_args(); + if ($numargs === 1 && is_array($arg_list[0])) + { + $arg_list = $arg_list[0]; + $numargs = count($arg_list); + } + + for ($i = 0; $i < $numargs; $i++) + { + $dir = realpath($arg_list[$i]); + + if (!is_dir($dir)) + { + continue; + } + + $dir = str_replace('\\', '/', $dir); + + // absolute path? + if (!self::isPathAbsolute($dir)) + { + $dir = $here_dir.'/'.$dir; + } + + $new_files = str_replace('\\', '/', $finder->search_in($dir)); + + if ($this->relative) + { + $new_files = preg_replace('#^'.preg_quote(rtrim($dir, '/'), '#').'/#', '', $new_files); + } + + $files = array_merge($files, $new_files); + } + + if ($this->sort === 'name') + { + sort($files); + } + + return array_unique($files); + } + + protected function search_in($dir, $depth = 0) + { + if ($depth > $this->maxdepth) + { + return array(); + } + + $dir = realpath($dir); + + if ((!$this->follow_link) && is_link($dir)) + { + return array(); + } + + $files = array(); + $temp_files = array(); + $temp_folders = array(); + if (is_dir($dir) && is_readable($dir)) + { + $current_dir = opendir($dir); + while (false !== $entryname = readdir($current_dir)) + { + if ($entryname == '.' || $entryname == '..') continue; + + $current_entry = $dir.DIRECTORY_SEPARATOR.$entryname; + if ((!$this->follow_link) && is_link($current_entry)) + { + continue; + } + + if (is_dir($current_entry)) + { + if ($this->sort === 'type') + { + $temp_folders[$entryname] = $current_entry; + } + else + { + if (($this->type === 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->exec_ok($dir, $entryname)) + { + $files[] = $current_entry; + } + + if (!$this->is_pruned($dir, $entryname)) + { + $files = array_merge($files, $this->search_in($current_entry, $depth + 1)); + } + } + } + else + { + if (($this->type !== 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->size_ok($dir, $entryname) && $this->exec_ok($dir, $entryname)) + { + if ($this->sort === 'type') + { + $temp_files[] = $current_entry; + } + else + { + $files[] = $current_entry; + } + } + } + } + + if ($this->sort === 'type') + { + ksort($temp_folders); + foreach($temp_folders as $entryname => $current_entry) + { + if (($this->type === 'directory' || $this->type === 'any') && ($depth >= $this->mindepth) && !$this->is_discarded($dir, $entryname) && $this->match_names($dir, $entryname) && $this->exec_ok($dir, $entryname)) + { + $files[] = $current_entry; + } + + if (!$this->is_pruned($dir, $entryname)) + { + $files = array_merge($files, $this->search_in($current_entry, $depth + 1)); + } + } + + sort($temp_files); + $files = array_merge($files, $temp_files); + } + + closedir($current_dir); + } + + return $files; + } + + protected function match_names($dir, $entry) + { + if (!count($this->names)) return true; + + // Flags indicating that there was attempts to match + // at least one "not_name" or "name" rule respectively + // to following variables: + $one_not_name_rule = false; + $one_name_rule = false; + + foreach ($this->names as $args) + { + list($not, $regex) = $args; + $not ? $one_not_name_rule = true : $one_name_rule = true; + if (preg_match($regex, $entry)) + { + // We must match ONLY ONE "not_name" or "name" rule: + // if "not_name" rule matched then we return "false" + // if "name" rule matched then we return "true" + return $not ? false : true; + } + } + + if ($one_not_name_rule && $one_name_rule) + { + return false; + } + else if ($one_not_name_rule) + { + return true; + } + else if ($one_name_rule) + { + return false; + } + return true; + } + + protected function size_ok($dir, $entry) + { + if (0 === count($this->sizes)) return true; + + if (!is_file($dir.DIRECTORY_SEPARATOR.$entry)) return true; + + $filesize = filesize($dir.DIRECTORY_SEPARATOR.$entry); + foreach ($this->sizes as $number_compare) + { + if (!$number_compare->test($filesize)) return false; + } + + return true; + } + + protected function is_pruned($dir, $entry) + { + if (0 === count($this->prunes)) return false; + + foreach ($this->prunes as $args) + { + $regex = $args[1]; + if (preg_match($regex, $entry)) return true; + } + + return false; + } + + protected function is_discarded($dir, $entry) + { + if (0 === count($this->discards)) return false; + + foreach ($this->discards as $args) + { + $regex = $args[1]; + if (preg_match($regex, $entry)) return true; + } + + return false; + } + + protected function exec_ok($dir, $entry) + { + if (0 === count($this->execs)) return true; + + foreach ($this->execs as $exec) + { + if (!call_user_func_array($exec, array($dir, $entry))) return false; + } + + return true; + } + + public static function isPathAbsolute($path) + { + if ($path{0} === '/' || $path{0} === '\\' || + (strlen($path) > 3 && ctype_alpha($path{0}) && + $path{1} === ':' && + ($path{2} === '\\' || $path{2} === '/') + ) + ) + { + return true; + } + + return false; + } +} + +/** + * Match globbing patterns against text. + * + * if match_glob("foo.*", "foo.bar") echo "matched\n"; + * + * // prints foo.bar and foo.baz + * $regex = glob_to_regex("foo.*"); + * for (array('foo.bar', 'foo.baz', 'foo', 'bar') as $t) + * { + * if (/$regex/) echo "matched: $car\n"; + * } + * + * sfGlobToRegex implements glob(3) style matching that can be used to match + * against text, rather than fetching names from a filesystem. + * + * based on perl Text::Glob module. + * + * @package symfony + * @subpackage util + * @author Fabien Potencier php port + * @author Richard Clamp perl version + * @copyright 2004-2005 Fabien Potencier + * @copyright 2002 Richard Clamp + * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $ + */ +class sfGlobToRegex +{ + protected static $strict_leading_dot = true; + protected static $strict_wildcard_slash = true; + + public static function setStrictLeadingDot($boolean) + { + self::$strict_leading_dot = $boolean; + } + + public static function setStrictWildcardSlash($boolean) + { + self::$strict_wildcard_slash = $boolean; + } + + /** + * Returns a compiled regex which is the equiavlent of the globbing pattern. + * + * @param string $glob pattern + * @return string regex + */ + public static function glob_to_regex($glob) + { + $first_byte = true; + $escaping = false; + $in_curlies = 0; + $regex = ''; + $sizeGlob = strlen($glob); + for ($i = 0; $i < $sizeGlob; $i++) + { + $car = $glob[$i]; + if ($first_byte) + { + if (self::$strict_leading_dot && $car !== '.') + { + $regex .= '(?=[^\.])'; + } + + $first_byte = false; + } + + if ($car === '/') + { + $first_byte = true; + } + + if ($car === '.' || $car === '(' || $car === ')' || $car === '|' || $car === '+' || $car === '^' || $car === '$') + { + $regex .= "\\$car"; + } + elseif ($car === '*') + { + $regex .= ($escaping ? '\\*' : (self::$strict_wildcard_slash ? '[^/]*' : '.*')); + } + elseif ($car === '?') + { + $regex .= ($escaping ? '\\?' : (self::$strict_wildcard_slash ? '[^/]' : '.')); + } + elseif ($car === '{') + { + $regex .= ($escaping ? '\\{' : '('); + if (!$escaping) ++$in_curlies; + } + elseif ($car === '}' && $in_curlies) + { + $regex .= ($escaping ? '}' : ')'); + if (!$escaping) --$in_curlies; + } + elseif ($car === ',' && $in_curlies) + { + $regex .= ($escaping ? ',' : '|'); + } + elseif ($car === '\\') + { + if ($escaping) + { + $regex .= '\\\\'; + $escaping = false; + } + else + { + $escaping = true; + } + + continue; + } + else + { + $regex .= $car; + } + $escaping = false; + } + + return '#^'.$regex.'$#'; + } +} + +/** + * Numeric comparisons. + * + * sfNumberCompare compiles a simple comparison to an anonymous + * subroutine, which you can call with a value to be tested again. + + * Now this would be very pointless, if sfNumberCompare didn't understand + * magnitudes. + + * The target value may use magnitudes of kilobytes (k, ki), + * megabytes (m, mi), or gigabytes (g, gi). Those suffixed + * with an i use the appropriate 2**n version in accordance with the + * IEC standard: http://physics.nist.gov/cuu/Units/binary.html + * + * based on perl Number::Compare module. + * + * @package symfony + * @subpackage util + * @author Fabien Potencier php port + * @author Richard Clamp perl version + * @copyright 2004-2005 Fabien Potencier + * @copyright 2002 Richard Clamp + * @see http://physics.nist.gov/cuu/Units/binary.html + * @version SVN: $Id: sfFinder.class.php 32891 2011-08-05 07:48:34Z fabien $ + */ +class sfNumberCompare +{ + protected $test = ''; + + public function __construct($test) + { + $this->test = $test; + } + + public function test($number) + { + if (!preg_match('{^([<>]=?)?(.*?)([kmg]i?)?$}i', $this->test, $matches)) + { + throw new sfException(sprintf('don\'t understand "%s" as a test.', $this->test)); + } + + $target = array_key_exists(2, $matches) ? $matches[2] : ''; + $magnitude = array_key_exists(3, $matches) ? $matches[3] : ''; + if (strtolower($magnitude) === 'k') $target *= 1000; + if (strtolower($magnitude) === 'ki') $target *= 1024; + if (strtolower($magnitude) === 'm') $target *= 1000000; + if (strtolower($magnitude) === 'mi') $target *= 1024*1024; + if (strtolower($magnitude) === 'g') $target *= 1000000000; + if (strtolower($magnitude) === 'gi') $target *= 1024*1024*1024; + + $comparison = array_key_exists(1, $matches) ? $matches[1] : '=='; + if ($comparison === '==' || $comparison == '') + { + return ($number == $target); + } + if ($comparison === '>') + { + return ($number > $target); + } + if ($comparison === '>=') + { + return ($number >= $target); + } + if ($comparison === '<') + { + return ($number < $target); + } + if ($comparison === '<=') + { + return ($number <= $target); + } + + return false; + } +} diff --git a/videos/preview-2.ogv b/videos/preview-2.ogv new file mode 100644 index 0000000..a3e5ac5 Binary files /dev/null and b/videos/preview-2.ogv differ diff --git a/website/logo.svg b/website/logo.svg new file mode 100644 index 0000000..0ddfbe4 --- /dev/null +++ b/website/logo.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + CMSInstaller + + +