From 018ea24ce8b31e12ff56b15143dae89091ff592f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 4 May 2017 14:00:24 +1200 Subject: [PATCH 01/11] MINOR: Better error message in SapphireTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This error usually occurs when you've added a module but haven't run flush on your test classes. I’ve made the error message more explicit. --- dev/SapphireTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index 21df46c13..97a3d8fc3 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -472,7 +472,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase { */ protected function getCurrentAbsolutePath() { $filename = self::$test_class_manifest->getItemPath(get_class($this)); - if(!$filename) throw new LogicException("getItemPath returned null for " . get_class($this)); + if(!$filename) throw new LogicException("getItemPath returned null for " . get_class($this) + . ". Try adding flush=1 to the test run."); return dirname($filename); } From 82c0632f46e00a251d287811652429036d200eff Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Wed, 26 Jul 2017 09:53:54 +0100 Subject: [PATCH 02/11] Fix: Use Config API for MemberAuthenticator::$migrate_legacy_hashes (fixes #7208) --- security/MemberAuthenticator.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/MemberAuthenticator.php b/security/MemberAuthenticator.php index bfa6a6f49..29005bb35 100644 --- a/security/MemberAuthenticator.php +++ b/security/MemberAuthenticator.php @@ -161,9 +161,10 @@ class MemberAuthenticator extends Authenticator { // when we can rehash passwords to a different hashing algorithm, // bulk-migration doesn't work due to the nature of hashing. // See PasswordEncryptor_LegacyPHPHash class. - if($success && $member && isset(self::$migrate_legacy_hashes[$member->PasswordEncryption])) { + $migrateLegacyHashes = self::config()->migrate_legacy_hashes; + if($success && $member && isset($migrateLegacyHashes[$member->PasswordEncryption])) { $member->Password = $data['Password']; - $member->PasswordEncryption = self::$migrate_legacy_hashes[$member->PasswordEncryption]; + $member->PasswordEncryption = $migrateLegacyHashes[$member->PasswordEncryption]; $member->write(); } From 31c5eebda089867d61546106b36ca20b21a00026 Mon Sep 17 00:00:00 2001 From: Daniel Hensby Date: Wed, 26 Jul 2017 11:20:00 +0100 Subject: [PATCH 03/11] FIX Avoid JS errors for HTMLEditorFields in small holders --- templates/forms/HtmlEditorField_holder_small.ss | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 templates/forms/HtmlEditorField_holder_small.ss diff --git a/templates/forms/HtmlEditorField_holder_small.ss b/templates/forms/HtmlEditorField_holder_small.ss new file mode 100644 index 000000000..21eec8dc5 --- /dev/null +++ b/templates/forms/HtmlEditorField_holder_small.ss @@ -0,0 +1,5 @@ +
+ <% if $Title %><% end_if %> + $Field + <% if $RightTitle %><% end_if %> +
From 6ad19495a225716ff6feeb70e721005d78cd5e8a Mon Sep 17 00:00:00 2001 From: Garion Herman Date: Mon, 22 May 2017 13:54:57 +1200 Subject: [PATCH 04/11] Add test coverage for auth failure after TempID expires. --- tests/security/MemberAuthenticatorTest.php | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/security/MemberAuthenticatorTest.php b/tests/security/MemberAuthenticatorTest.php index 8606e6f58..9f2310122 100644 --- a/tests/security/MemberAuthenticatorTest.php +++ b/tests/security/MemberAuthenticatorTest.php @@ -137,6 +137,44 @@ class MemberAuthenticatorTest extends SapphireTest { $this->assertEquals('bad', $form->MessageType()); } + public function testExpiredTempID() + { + //store original default admin as we'll need to clear it + $adminUser = Security::default_admin_username(); + $adminPass = Security::default_admin_password(); + + // Make member with expired TempID + $member = new Member(); + $member->Email = 'test1@test.com'; + $member->PasswordEncryption = "sha1"; + $member->Password = "mypassword"; + $member->TempIDExpired = '2016-05-22 00:00:00'; + $member->write(); + $member->logIn(true); + + $tempID = $member->TempIDHash; + + // Make form + $controller = new Security(); + $form = new Form($controller, 'Form', new FieldList(), new FieldList()); + + SS_Datetime::set_mock_now('2016-05-29 00:00:00'); + Security::clear_default_admin(); + + $this->assertNotEmpty($tempID); + $this->assertFalse(Security::has_default_admin()); + + $result = MemberAuthenticator::authenticate(array( + 'tempid' => $tempID, + 'Password' => 'notmypassword' + ), $form); + $this->assertEmpty($result); + + if (!is_null($adminUser) || !is_null($adminPass)) { + Security::setDefaultAdmin($adminUser, $adminPass); + } + } + /** * Test that the default admin can be authenticated */ From 6494bc820ccf4ae0230c0b6b0ba89de06012ecf4 Mon Sep 17 00:00:00 2001 From: Daniel Hensby Date: Fri, 28 Jul 2017 13:21:29 +0100 Subject: [PATCH 05/11] Move spyc dependency to composer --- composer.json | 3 +- dev/YamlFixture.php | 2 - thirdparty/spyc/.gitignore | 2 - thirdparty/spyc/.piston.yml | 8 - thirdparty/spyc/README | 159 ----- thirdparty/spyc/php4/5to4.php | 16 - thirdparty/spyc/php4/spyc.php4 | 778 ------------------------ thirdparty/spyc/php4/test.php4 | 162 ----- thirdparty/spyc/spyc.php | 1014 -------------------------------- thirdparty/spyc/spyc.yaml | 183 ------ 10 files changed, 2 insertions(+), 2325 deletions(-) delete mode 100644 thirdparty/spyc/.gitignore delete mode 100644 thirdparty/spyc/.piston.yml delete mode 100644 thirdparty/spyc/README delete mode 100644 thirdparty/spyc/php4/5to4.php delete mode 100644 thirdparty/spyc/php4/spyc.php4 delete mode 100644 thirdparty/spyc/php4/test.php4 delete mode 100644 thirdparty/spyc/spyc.php delete mode 100644 thirdparty/spyc/spyc.yaml diff --git a/composer.json b/composer.json index a0325d6e0..bdbd63c6c 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": ">=5.3.3,<7", - "composer/installers": "~1.0" + "composer/installers": "~1.0", + "mustangostang/spyc": "^0.6.2" }, "require-dev": { "phpunit/PHPUnit": "~3.7" diff --git a/dev/YamlFixture.php b/dev/YamlFixture.php index 291ab4f6b..c6eea991d 100644 --- a/dev/YamlFixture.php +++ b/dev/YamlFixture.php @@ -1,7 +1,5 @@ > $readme = Spyc::YAMLLoad('README'); -# ---- %YAML:1.1 -title: Spyc -- a Simple PHP YAML Class -version: 0.4.2 -author: [chris wanstrath, chris@ozmm.org] -websites: [http://www.yaml.org, http://spyc.sourceforge.net] -license: [MIT License, http://www.opensource.org/licenses/mit-license.php] -copyright: (c) 2005-2006 Chris Wanstrath -tested on: [php 5.2] - -installation: > - Copy spyc.php to a directory you can - access with your YAML-ready PHP script. - - That's it! - -about: > - From www.yaml.org: - - "YAML(tm) (rhymes with 'camel') is a human-friendly, cross language, - Unicode based data serialization language designed around the common - native data structures of agile programming languages. It is broadly - useful for programming needs ranging from configuration files to - Internet messaging to object persistence to data auditing. Together - with the Unicode standard for characters, the YAML specification provides - all the information necessary to understand YAML Version 1.1 and to - creating programs that process YAML information. - - YAML(tm) is a balance of the following design goals: - - YAML documents are very readable by humans. - - YAML interacts well with scripting languages. - - YAML uses host languages' native data structures. - - YAML has a consistent information model. - - YAML enables stream-based processing. - - YAML is expressive and extensible. - - YAML is easy to implement." - - YAML makes a lot of sense. It's easy to use, easy to learn, and cool. - As the lucky stiff named why once said, "YAML is a beacon of light." - - If you're new to YAML, may we suggest YAML In Five Minutes: - - http://yaml.kwiki.org/?YamlInFiveMinutes - - If you don't have five minutes, realize that this README is a completely - valid YAML document. Dig in, load this or any YAML file into an array - with Spyc and see how easy it is to translate friendly text into usable - data. - - The purpose of Spyc is to provide a pure PHP alternative to Syck, a - simple API for loading and dumping YAML documents, a YAML loader which - understands a usable subset of the YAML spec, and to further spread - the glory of YAML to the PHP masses. - - If you're at all hesitant ("usable subset of YAML?!"), navigate - http://yaml.org/start.html. Spyc completely understands the YAML - document shown there, a document which has features way beyond the - scope of what normal config files might require. Try it for yourself, - and then start enjoying the peace of mind YAML brings to your life. - -meat and a few potatoes: - - concept: Loading a YAML document into PHP - brief: > - $yaml will become an array of all the data in wicked.yaml - code: | - - include('spyc.php'); - - $yaml = Spyc::YAMLLoad('wicked.yaml'); - - - concept: Loading a YAML string into PHP - brief: > - $array will look like this: - array('A YAML','document in a','string') - code: | - - include('spyc.php'); - - $yaml = '- A YAML\n- document in a\n- string.'; - $array = Spyc::YAMLLoad($yaml); - - - concept: Dumping a PHP array to YAML - brief: > - $yaml will become a string of a YAML document created from - $array. - code: | - - include('spyc.php'); - - $array['name'] = 'chris'; - $array['sport'] = 'curbing'; - - $yaml = Spyc::YAMLDump($array); - -prior art: - - who: [Brian Ingerson, Clark Evans, Oren Ben-Kiki] - why?: > - The YAML spec is really a piece of work, and these guys - did a great job on it. A simple and elegant language like - YAML was a long time coming and it's refreshing to know - such able minded individuals took the task to heart and - executed it with cunning and strength. In addition to - their various noteworthy contributions to YAML parsers - and related projects, YAML.pm's README is a treasure trove - of information for knowledge seekers. Thanks, guys. - - - who: why the lucky stiff - why?: > - As the author of Syck, the code used in Ruby for the language's - YAML class and methods, why is indirectly (directly?) responsible - for my first exposure to YAML (as a config file in a Ruby web-app) - and the countless hours I spent playing with this sheik new data - format afterwards. Syck's README is a YAML file and thus the - inspiration for this file and, even, this very piece of software. - - - who: Steve Howell - why?: > - Python's YAML implementation. PyYAML's README file is also YAML, - so it too inspired the YAML format of this README file. - - - who: [Rasmus Lerdorf, Zeev Suraski, Andi Gutmans, et al] - why?: > - PHP is great at what it does best. It's also paid a lot of my bills. - Thanks. - -bugs: - report: > - Please see Spyc's Sourceforge project page for information on reporting bugs. - speed: > - This implementation was not designed for speed. Rather, it - was designed for those who need a pure PHP implementation of - a YAML parser and who are not overly concerned with performance. - If you want speed, check out Syck. - depth: > - This parser is by no means a comprehensive YAML parser. For supported - features and future plans, check the website. - unicode: > - YAML is supposed to be unicode, but for now we're just using ASCII. - PHP has crappy unicode support but who knows what the future holds. - -resources: - - http://www.yaml.org - - http://www.yaml.org/spec/ - - http://yaml.kwiki.org/?YamlInFiveMinutes - - http://www.whytheluckystiff.net/syck/ - - http://yaml4r.sourceforge.net/cookbook/ - -thanks: - - Adam Wood - - Daniel Ferreira - - Aaron Jensen - - Mike Thornton - - Fabien Potencier - - Mustafa Kumas \ No newline at end of file diff --git a/thirdparty/spyc/php4/5to4.php b/thirdparty/spyc/php4/5to4.php deleted file mode 100644 index 2f2af7970..000000000 --- a/thirdparty/spyc/php4/5to4.php +++ /dev/null @@ -1,16 +0,0 @@ -', $code); - $f = fopen ($dest, 'w'); - fwrite($f, $code); - fclose ($f); - print "Written to $dest.\n"; -} diff --git a/thirdparty/spyc/php4/spyc.php4 b/thirdparty/spyc/php4/spyc.php4 deleted file mode 100644 index dc5a771c1..000000000 --- a/thirdparty/spyc/php4/spyc.php4 +++ /dev/null @@ -1,778 +0,0 @@ - - * @author Vlad Andersen - * @link http://spyc.sourceforge.net/ - * @copyright Copyright 2005-2006 Chris Wanstrath - * @license http://www.opensource.org/licenses/mit-license.php MIT License - * @package Spyc - */ -/** - * The Simple PHP YAML Class. - * - * This class can be used to read a YAML file and convert its contents - * into a PHP array. It currently supports a very limited subsection of - * the YAML spec. - * - * Usage: - * - * $parser = new Spyc; - * $array = $parser->load($file); - * - * @package Spyc - */ -class Spyc { - - /**#@+ - * @access private - * @var mixed - */ - var $_haveRefs; - var $_allNodes; - var $_allParent; - var $_lastIndent; - var $_lastNode; - var $_inBlock; - var $_isInline; - var $_dumpIndent; - var $_dumpWordWrap; - var $_containsGroupAnchor = false; - var $_containsGroupAlias = false; - var $path; - var $result; - var $LiteralBlockMarkers = array ('>', '|'); - var $LiteralPlaceHolder = '___YAML_Literal_Block___'; - var $SavedGroups = array(); - - /**#@+ - * @access public - * @var mixed - */ - var $_nodeId; - - /** - * Load YAML into a PHP array statically - * - * 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. Pretty - * simple. - * Usage: - * - * $array = Spyc::YAMLLoad('lucky.yaml'); - * print_r($array); - * - * @access public - * @return array - * @param string $input Path of YAML file or string containing YAML - */ - function YAMLLoad($input) { - $Spyc = new Spyc; - return $Spyc->load($input); - } - - /** - * Dump YAML from PHP array statically - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as nothing.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - function YAMLDump($array,$indent = false,$wordwrap = false) { - $spyc = new Spyc; - return $spyc->dump($array,$indent,$wordwrap); - } - - - /** - * Dump PHP array to YAML - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as tasteful.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - function dump($array,$indent = false,$wordwrap = false) { - // Dumps to some very clean YAML. We'll have to add some more features - // and options soon. And better support for folding. - - // New features and options. - if ($indent === false or !is_numeric($indent)) { - $this->_dumpIndent = 2; - } else { - $this->_dumpIndent = $indent; - } - - if ($wordwrap === false or !is_numeric($wordwrap)) { - $this->_dumpWordWrap = 40; - } else { - $this->_dumpWordWrap = $wordwrap; - } - - // New YAML document - $string = "---\n"; - - // Start at the base of the array and move through it. - foreach ($array as $key => $value) { - $string .= $this->_yamlize($key,$value,0); - } - return $string; - } - - /** - * Attempts to convert a key / value array item to YAML - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - function _yamlize($key,$value,$indent) { - if (is_array($value)) { - // It has children. What to do? - // Make it the right kind of item - $string = $this->_dumpNode($key,NULL,$indent); - // Add the indent - $indent += $this->_dumpIndent; - // Yamlize the array - $string .= $this->_yamlizeArray($value,$indent); - } elseif (!is_array($value)) { - // It doesn't have children. Yip. - $string = $this->_dumpNode($key,$value,$indent); - } - return $string; - } - - /** - * Attempts to convert an array to YAML - * @access private - * @return string - * @param $array The array you want to convert - * @param $indent The indent of the current level - */ - function _yamlizeArray($array,$indent) { - if (is_array($array)) { - $string = ''; - foreach ($array as $key => $value) { - $string .= $this->_yamlize($key,$value,$indent); - } - return $string; - } else { - return false; - } - } - - /** - * Returns YAML from a key and a value - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - function _dumpNode($key,$value,$indent) { - // do some folding here, for blocks - if (strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false) { - $value = $this->_doLiteralBlock($value,$indent); - } else { - $value = $this->_doFolding($value,$indent); - } - - if (is_bool($value)) { - $value = ($value) ? "true" : "false"; - } - - $spaces = str_repeat(' ',$indent); - - if (is_int($key)) { - // It's a sequence - $string = $spaces.'- '.$value."\n"; - } else { - // It's mapped - if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; } - $string = $spaces.$key.': '.$value."\n"; - } - return $string; - } - - /** - * Creates a literal block for dumping - * @access private - * @return string - * @param $value - * @param $indent int The value of the indent - */ - function _doLiteralBlock($value,$indent) { - $exploded = explode("\n",$value); - $newValue = '|'; - $indent += $this->_dumpIndent; - $spaces = str_repeat(' ',$indent); - foreach ($exploded as $line) { - $newValue .= "\n" . $spaces . trim($line); - } - return $newValue; - } - - /** - * Folds a string of text, if necessary - * @access private - * @return string - * @param $value The string you wish to fold - */ - function _doFolding($value,$indent) { - // Don't do anything if wordwrap is set to 0 - if ($this->_dumpWordWrap === 0) { - return $value; - } - - if (strlen($value) > $this->_dumpWordWrap) { - $indent += $this->_dumpIndent; - $indent = str_repeat(' ',$indent); - $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); - $value = ">\n".$indent.$wrapped; - } - return $value; - } - -/* LOADING FUNCTIONS */ - - function load($input) { - $Source = $this->loadFromSource($input); - if (empty ($Source)) return array(); - $this->path = array(); - $this->result = array(); - - - for ($i = 0; $i < count($Source); $i++) { - $line = $Source[$i]; - $lineIndent = $this->_getIndent($line); - $this->path = $this->getParentPathByIndent($lineIndent); - $line = $this->stripIndent($line, $lineIndent); - if ($this->isComment($line)) continue; - - if ($literalBlockStyle = $this->startsLiteralBlock($line)) { - $line = rtrim ($line, $literalBlockStyle . "\n"); - $literalBlock = ''; - $line .= $this->LiteralPlaceHolder; - - while (++$i < count($Source) && $this->literalBlockContinues($Source[$i], $lineIndent)) { - $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle); - } - $i--; - } - $lineArray = $this->_parseLine($line); - - if ($literalBlockStyle) - $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); - - $this->addArray($lineArray, $lineIndent); - } - return $this->result; - } - - function loadFromSource ($input) { - if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) - return file($input); - - $foo = explode("\n",$input); - foreach ($foo as $k => $_) { - $foo[$k] = trim ($_, "\r"); - } - return $foo; - } - - /** - * Finds and returns the indentation of a YAML line - * @access private - * @return int - * @param string $line A line from the YAML file - */ - function _getIndent($line) { - if (!preg_match('/^ +/',$line,$match)) return 0; - if (!empty($match[0])) return strlen ($match[0]); - return 0; - } - - /** - * Parses YAML code and returns an array for a node - * @access private - * @return array - * @param string $line A line from the YAML file - */ - function _parseLine($line) { - if (!$line) return array(); - $line = trim($line); - if (!$line) return array(); - $array = array(); - - if ($group = $this->nodeContainsGroup($line)) { - $this->addGroup($line, $group); - $line = $this->stripGroup ($line, $group); - } - - if ($this->startsMappedSequence($line)) - return $this->returnMappedSequence($line); - - if ($this->startsMappedValue($line)) - return $this->returnMappedValue($line); - - if ($this->isArrayElement($line)) - return $this->returnArrayElement($line); - - if ($this->isPlainArray($line)) - return $this->returnPlainArray($line); - - return $this->returnKeyValuePair($line); - - } - - - - /** - * Finds the type of the passed value, returns the value as the new type. - * @access private - * @param string $value - * @return mixed - */ - function _toType($value) { - - if (strpos($value, '#') !== false) - $value = trim(preg_replace('/#(.+)$/','',$value)); - - if (preg_match('/^("(.*)"|\'(.*)\')/',$value,$matches)) { - $value = (string)preg_replace('/(\'\'|\\\\\')/',"'",end($matches)); - $value = preg_replace('/\\\\"/','"',$value); - } elseif (preg_match('/^\\[(.+)\\]$/',$value,$matches)) { - // Inline Sequence - - // Take out strings sequences and mappings - $explode = $this->_inlineEscape($matches[1]); - - // Propagate value array - $value = array(); - foreach ($explode as $v) { - $value[] = $this->_toType($v); - } - } elseif (strpos($value,': ')!==false && !preg_match('/^{(.+)/',$value)) { - // It's a map - $array = explode(': ',$value); - $key = trim($array[0]); - array_shift($array); - $value = trim(implode(': ',$array)); - $value = $this->_toType($value); - $value = array($key => $value); - } elseif (preg_match("/{(.+)}$/",$value,$matches)) { - // Inline Mapping - - // Take out strings sequences and mappings - $explode = $this->_inlineEscape($matches[1]); - - // Propogate value array - $array = array(); - foreach ($explode as $v) { - $SubArr = $this->_toType($v); - if (empty($SubArr)) continue; - if (is_array ($SubArr)) { - $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; - } - $array[] = $SubArr; - } - $value = $array; - } elseif (strtolower($value) == 'null' or $value == '' or $value == '~') { - $value = null; - } elseif (preg_match ('/^[0-9]+$/', $value)) { - $value = (int)$value; - } elseif (in_array(strtolower($value), - array('true', 'on', '+', 'yes', 'y'))) { - $value = true; - } elseif (in_array(strtolower($value), - array('false', 'off', '-', 'no', 'n'))) { - $value = false; - } elseif (is_numeric($value)) { - $value = (float)$value; - } else { - // Just a normal string, right? - - } - - - // print_r ($value); - return $value; - } - - /** - * Used in inlines to check for more inlines or quoted strings - * @access private - * @return array - */ - function _inlineEscape($inline) { - // There's gotta be a cleaner way to do this... - // While pure sequences seem to be nesting just fine, - // pure mappings and mappings with sequences inside can't go very - // deep. This needs to be fixed. - - $saved_strings = array(); - - // Check for strings - $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; - if (preg_match_all($regex,$inline,$strings)) { - $saved_strings = $strings[0]; - $inline = preg_replace($regex,'YAMLString',$inline); - } - unset($regex); - - // Check for sequences - if (preg_match_all('/\[(.+)\]/U',$inline,$seqs)) { - $inline = preg_replace('/\[(.+)\]/U','YAMLSeq',$inline); - $seqs = $seqs[0]; - } - - // Check for mappings - if (preg_match_all('/{(.+)}/U',$inline,$maps)) { - $inline = preg_replace('/{(.+)}/U','YAMLMap',$inline); - $maps = $maps[0]; - } - - $explode = explode(', ',$inline); - - - // Re-add the sequences - if (!empty($seqs)) { - $i = 0; - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLSeq') !== false) { - $explode[$key] = str_replace('YAMLSeq',$seqs[$i],$value); - ++$i; - } - } - } - - // Re-add the mappings - if (!empty($maps)) { - $i = 0; - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLMap') !== false) { - $explode[$key] = str_replace('YAMLMap',$maps[$i],$value); - ++$i; - } - } - } - - - // Re-add the strings - if (!empty($saved_strings)) { - $i = 0; - foreach ($explode as $key => $value) { - while (strpos($value,'YAMLString') !== false) { - $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$i],$value, 1); - ++$i; - $value = $explode[$key]; - } - } - } - - return $explode; - } - - function literalBlockContinues ($line, $lineIndent) { - if (!trim($line)) return true; - if ($this->_getIndent($line) > $lineIndent) return true; - return false; - } - - function addArrayInline ($array, $indent) { - $CommonGroupPath = $this->path; - if (empty ($array)) return false; - - foreach ($array as $k => $_) { - $this->addArray(array($k => $_), $indent); - $this->path = $CommonGroupPath; - } - return true; - } - - function addArray ($array, $indent) { - if (count ($array) > 1) - return $this->addArrayInline ($array, $indent); - - - $key = key ($array); - if (!isset ($array[$key])) return false; - if ($array[$key] === array()) { $array[$key] = ''; }; - $value = $array[$key]; - - // Unfolding inner array tree as defined in $this->_arrpath. - //$_arr = $this->result; $_tree[0] = $_arr; $i = 1; - - $tempPath = Spyc::flatten ($this->path); - eval ('$_arr = $this->result' . $tempPath . ';'); - - - if ($this->_containsGroupAlias) { - do { - if (!isset($this->SavedGroups[$this->_containsGroupAlias])) { echo "Bad group name: $this->_containsGroupAlias."; break; } - $groupPath = $this->SavedGroups[$this->_containsGroupAlias]; - eval ('$value = $this->result' . Spyc::flatten ($groupPath) . ';'); - } while (false); - $this->_containsGroupAlias = false; - } - - - // Adding string or numeric key to the innermost level or $this->arr. - if ($key) - $_arr[$key] = $value; - else { - if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } - else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } - - } - - $this->path[$indent] = $key; - - eval ('$this->result' . $tempPath . ' = $_arr;'); - - if ($this->_containsGroupAnchor) { - $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; - $this->_containsGroupAnchor = false; - } - - - } - - - function flatten ($array) { - $tempPath = array(); - if (!empty ($array)) { - foreach ($array as $_) { - if (!is_int($_)) $_ = "'$_'"; - $tempPath[] = "[$_]"; - } - } - //end ($tempPath); $latestKey = key($tempPath); - $tempPath = implode ('', $tempPath); - return $tempPath; - } - - - - function startsLiteralBlock ($line) { - $lastChar = substr (trim($line), -1); - if (in_array ($lastChar, $this->LiteralBlockMarkers)) - return $lastChar; - return false; - } - - function addLiteralLine ($literalBlock, $line, $literalBlockStyle) { - $line = $this->stripIndent($line); - $line = str_replace ("\r\n", "\n", $line); - - if ($literalBlockStyle == '|') { - return $literalBlock . $line; - } - if (strlen($line) == 0) return $literalBlock . "\n"; - - // echo "|$line|"; - if ($line != "\n") - $line = trim ($line, "\r\n ") . " "; - - return $literalBlock . $line; - } - - function revertLiteralPlaceHolder ($lineArray, $literalBlock) { - - foreach ($lineArray as $k => $_) { - if (is_array($_)) - $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); - else{ - if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) - $lineArray[$k] = rtrim ($literalBlock, " \r\n"); - } - } - return $lineArray; - } - - function stripIndent ($line, $indent = -1) { - if ($indent == -1) $indent = $this->_getIndent($line); - return substr ($line, $indent); - } - - function getParentPathByIndent ($indent) { - - if ($indent == 0) return array(); - - $linePath = $this->path; - do { - end($linePath); $lastIndentInParentPath = key($linePath); - if ($indent <= $lastIndentInParentPath) array_pop ($linePath); - } while ($indent <= $lastIndentInParentPath); - return $linePath; - } - - - function clearBiggerPathValues ($indent) { - - - if ($indent == 0) $this->path = array(); - if (empty ($this->path)) return true; - - foreach ($this->path as $k => $_) { - if ($k > $indent) unset ($this->path[$k]); - } - - return true; - } - - - function isComment ($line) { - if (preg_match('/^#/', $line)) return true; - if (trim($line, " \r\n\t") == '---') return true; - return false; - } - - function isArrayElement ($line) { - if (!$line) return false; - if ($line[0] != '-') return false; - if (strlen ($line) > 3) - if (substr($line,0,3) == '---') return false; - - return true; - } - - function isHashElement ($line) { - if (!preg_match('/^(.+?):/', $line, $matches)) return false; - $allegedKey = $matches[1]; - if ($allegedKey) return true; - //if (substr_count($allegedKey, ) - return false; - } - - function isLiteral ($line) { - if ($this->isArrayElement($line)) return false; - if ($this->isHashElement($line)) return false; - return true; - } - - - function startsMappedSequence ($line) { - if (preg_match('/^-(.*):$/',$line)) return true; - } - - function returnMappedSequence ($line) { - $array = array(); - $key = trim(substr(substr($line,1),0,-1)); - $array[$key] = ''; - return $array; - } - - function returnMappedValue ($line) { - $array = array(); - $key = trim(substr($line,0,-1)); - $array[$key] = ''; - return $array; - } - - function startsMappedValue ($line) { - if (preg_match('/^(.*):$/',$line)) return true; - } - - function isPlainArray ($line) { - if (preg_match('/^\[(.*)\]$/', $line)) return true; - return false; - } - - function returnPlainArray ($line) { - return $this->_toType($line); - } - - function returnKeyValuePair ($line) { - - $array = array(); - - if (preg_match('/^(.+):/',$line,$key)) { - // It's a key/value pair most likely - // If the key is in double quotes pull it out - if (preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { - $value = trim(str_replace($matches[1],'',$line)); - $key = $matches[2]; - } else { - // Do some guesswork as to the key and the value - $explode = explode(':',$line); - $key = trim($explode[0]); - array_shift($explode); - $value = trim(implode(':',$explode)); - } - - // Set the type of the value. Int, string, etc - $value = $this->_toType($value); - if (empty($key)) { - $array[] = $value; - } else { - $array[$key] = $value; - } - } - - return $array; - - } - - - function returnArrayElement ($line) { - if (strlen($line) <= 1) return array(array()); // Weird %) - $array = array(); - $value = trim(substr($line,1)); - $value = $this->_toType($value); - $array[] = $value; - return $array; - } - - - function nodeContainsGroup ($line) { - $symbolsForReference = 'A-z0-9_\-'; - if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) - if (preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if (preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if (preg_match('/(&['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; - if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; - return false; - } - - function addGroup ($line, $group) { - if (substr ($group, 0, 1) == '&') $this->_containsGroupAnchor = substr ($group, 1); - if (substr ($group, 0, 1) == '*') $this->_containsGroupAlias = substr ($group, 1); - //print_r ($this->path); - } - - function stripGroup ($line, $group) { - $line = trim(str_replace($group, '', $line)); - return $line; - } - - -} -?> diff --git a/thirdparty/spyc/php4/test.php4 b/thirdparty/spyc/php4/test.php4 deleted file mode 100644 index 0e4b18400..000000000 --- a/thirdparty/spyc/php4/test.php4 +++ /dev/null @@ -1,162 +0,0 @@ - "1.5ghz", "ram" => "1 gig", - "os" => "os x 10.4.1")) - die('Sequence 4 failed'); - -# Mapped sequence -if ($yaml['domains'] != array("yaml.org", "php.net")) - die("Key: 'domains' failed"); - -# A sequence like this. -if ($yaml[5] != array("program" => "Adium", "platform" => "OS X", - "type" => "Chat Client")) - die('Sequence 5 failed'); - -# A folded block as a mapped value -if ($yaml['no time'] != "There isn't any time for your tricks! \nDo you understand?") - die("Key: 'no time' failed"); - -# A literal block as a mapped value -if ($yaml['some time'] != "There is nothing but time\nfor your tricks.") - die("Key: 'some time' failed"); - -# Crazy combinations -if ($yaml['databases'] != array( array("name" => "spartan", "notes" => - array( "Needs to be backed up", - "Needs to be normalized" ), - "type" => "mysql" ))) - die("Key: 'databases' failed"); - -# You can be a bit tricky -if ($yaml["if: you'd"] != "like") - die("Key: 'if: you\'d' failed"); - -# Inline sequences -if ($yaml[6] != array("One", "Two", "Three", "Four")) - die("Sequence 6 failed"); - -# Nested Inline Sequences -if ($yaml[7] != array("One", array("Two", "And", "Three"), "Four", "Five")) - die("Sequence 7 failed"); - -# Nested Nested Inline Sequences -if ($yaml[8] != array( "This", array("Is", "Getting", array("Ridiculous", "Guys")), - "Seriously", array("Show", "Mercy"))) - die("Sequence 8 failed"); - -# Inline mappings -if ($yaml[9] != array("name" => "chris", "age" => "young", "brand" => "lucky strike")) - die("Sequence 9 failed"); - -# Nested inline mappings -if ($yaml[10] != array("name" => "mark", "age" => "older than chris", - "brand" => array("marlboro", "lucky strike"))) - die("Sequence 10 failed"); - -# References -- they're shaky, but functional -if ($yaml['dynamic languages'] != array('Perl', 'Python', 'PHP', 'Ruby')) - die("Key: 'dynamic languages' failed"); - -if ($yaml['compiled languages'] != array('C/C++', 'Java')) - die("Key: 'compiled languages' failed"); - -if ($yaml['all languages'] != array( - array('Perl', 'Python', 'PHP', 'Ruby'), - array('C/C++', 'Java') - )) - die("Key: 'all languages' failed"); - -# Added in .2.2: Escaped quotes -if ($yaml[11] != "you know, this shouldn't work. but it does.") - die("Sequence 11 failed."); - -if ($yaml[12] != "that's my value.") - die("Sequence 12 failed."); - -if ($yaml[13] != "again, that's my value.") - die("Sequence 13 failed."); - -if ($yaml[14] != "here's to \"quotes\", boss.") - die("Sequence 14 failed."); - -if ($yaml[15] != array( 'name' => "Foo, Bar's", 'age' => 20)) - die("Sequence 15 failed."); - -if ($yaml[16] != array( 0 => "a", 1 => array (0 => 1, 1 => 2), 2 => "b")) - die("Sequence 16 failed."); - -if ($yaml['endloop'] != "Does this line in the end indeed make Spyc go to an infinite loop?") - die("[endloop] failed."); - - -print "spyc.yaml parsed correctly\n"; - -?> \ No newline at end of file diff --git a/thirdparty/spyc/spyc.php b/thirdparty/spyc/spyc.php deleted file mode 100644 index fb11c6646..000000000 --- a/thirdparty/spyc/spyc.php +++ /dev/null @@ -1,1014 +0,0 @@ - - * @author Chris Wanstrath - * @link http://code.google.com/p/spyc/ - * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen - * @license http://www.opensource.org/licenses/mit-license.php MIT License - * @package Spyc - */ - -if (!function_exists('spyc_load')) { - /** - * Parses YAML to array. - * @param string $string YAML string. - * @return array - */ - function spyc_load ($string) { - return Spyc::YAMLLoadString($string); - } -} - -if (!function_exists('spyc_load_file')) { - /** - * Parses YAML to array. - * @param string $file Path to YAML file. - * @return array - */ - function spyc_load_file ($file) { - return Spyc::YAMLLoad($file); - } -} - -/** - * The Simple PHP YAML Class. - * - * This class can be used to read a YAML file and convert its contents - * into a PHP array. It currently supports a very limited subsection of - * the YAML spec. - * - * Usage: - * - * $Spyc = new Spyc; - * $array = $Spyc->load($file); - * - * or: - * - * $array = Spyc::YAMLLoad($file); - * - * or: - * - * $array = spyc_load_file($file); - * - * @package Spyc - */ -class Spyc { - - // SETTINGS - - /** - * Setting this to true will force YAMLDump to enclose any string value in - * quotes. False by default. - * - * @var bool - */ - public $setting_dump_force_quotes = false; - - /** - * Setting this to true will forse YAMLLoad to use syck_load function when - * possible. False by default. - * @var bool - */ - public $setting_use_syck_is_possible = false; - - - - /**#@+ - * @access private - * @var mixed - */ - private $_dumpIndent; - private $_dumpWordWrap; - private $_containsGroupAnchor = false; - private $_containsGroupAlias = false; - private $path; - private $result; - private $LiteralPlaceHolder = '___YAML_Literal_Block___'; - private $SavedGroups = array(); - private $indent; - /** - * Path modifier that should be applied after adding current element. - * @var array - */ - private $delayedPath = array(); - - /**#@+ - * @access public - * @var mixed - */ - public $_nodeId; - -/** - * Load a valid YAML string to Spyc. - * @param string $input - * @return array - */ - public function load ($input) { - return $this->__loadString($input); - } - - /** - * Load a valid YAML file to Spyc. - * @param string $file - * @return array - */ - public function loadFile ($file) { - return $this->__load($file); - } - - /** - * Load YAML into a PHP array statically - * - * 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. Pretty - * simple. - * Usage: - * - * $array = Spyc::YAMLLoad('lucky.yaml'); - * print_r($array); - * - * @access public - * @return array - * @param string $input Path of YAML file or string containing YAML - */ - public static function YAMLLoad($input) { - $Spyc = new Spyc; - return $Spyc->__load($input); - } - - /** - * Load a string of YAML into a PHP array statically - * - * The load method, when supplied with a YAML string, will do its best - * to convert YAML in a string into a PHP array. Pretty simple. - * - * Note: use this function if you don't want files from the file system - * loaded and processed as YAML. This is of interest to people concerned - * about security whose input is from a string. - * - * Usage: - * - * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); - * print_r($array); - * - * @access public - * @return array - * @param string $input String containing YAML - */ - public static function YAMLLoadString($input) { - $Spyc = new Spyc; - return $Spyc->__loadString($input); - } - - /** - * Dump YAML from PHP array statically - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as nothing.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - public static function YAMLDump($array,$indent = false,$wordwrap = false) { - $spyc = new Spyc; - return $spyc->dump($array,$indent,$wordwrap); - } - - - /** - * Dump PHP array to YAML - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. Pretty simple. Feel free to - * save the returned string as tasteful.yaml and pass it around. - * - * Oh, and you can decide how big the indent is and what the wordwrap - * for folding is. Pretty cool -- just pass in 'false' for either if - * you want to use the default. - * - * Indent's default is 2 spaces, wordwrap's default is 40 characters. And - * you can turn off wordwrap by passing in 0. - * - * @access public - * @return string - * @param array $array PHP array - * @param int $indent Pass in false to use the default, which is 2 - * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) - */ - public function dump($array,$indent = false,$wordwrap = false) { - // Dumps to some very clean YAML. We'll have to add some more features - // and options soon. And better support for folding. - - // New features and options. - if ($indent === false or !is_numeric($indent)) { - $this->_dumpIndent = 2; - } else { - $this->_dumpIndent = $indent; - } - - if ($wordwrap === false or !is_numeric($wordwrap)) { - $this->_dumpWordWrap = 40; - } else { - $this->_dumpWordWrap = $wordwrap; - } - - // New YAML document - $string = "---\n"; - - // Start at the base of the array and move through it. - if ($array) { - $array = (array)$array; - $first_key = key($array); - - $previous_key = -1; - foreach ($array as $key => $value) { - $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key); - $previous_key = $key; - } - } - return $string; - } - - /** - * Attempts to convert a key / value array item to YAML - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) { - if (is_array($value)) { - if (empty ($value)) - return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key); - // It has children. What to do? - // Make it the right kind of item - $string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key); - // Add the indent - $indent += $this->_dumpIndent; - // Yamlize the array - $string .= $this->_yamlizeArray($value,$indent); - } elseif (!is_array($value)) { - // It doesn't have children. Yip. - $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key); - } - return $string; - } - - /** - * Attempts to convert an array to YAML - * @access private - * @return string - * @param $array The array you want to convert - * @param $indent The indent of the current level - */ - private function _yamlizeArray($array,$indent) { - if (is_array($array)) { - $string = ''; - $previous_key = -1; - $first_key = key($array); - foreach ($array as $key => $value) { - $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key); - $previous_key = $key; - } - return $string; - } else { - return false; - } - } - - /** - * Returns YAML from a key and a value - * @access private - * @return string - * @param $key The name of the key - * @param $value The value of the item - * @param $indent The indent of the current node - */ - private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) { - // do some folding here, for blocks - if (is_string ($value) && (strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false || - strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || - strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':') { - $value = $this->_doLiteralBlock($value,$indent); - } else { - $value = $this->_doFolding($value,$indent); - if (is_bool($value)) { - $value = ($value) ? "true" : "false"; - } - } - - if ($value === array()) $value = '[ ]'; - - $spaces = str_repeat(' ',$indent); - - if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { - // It's a sequence - $string = $spaces.'- '.$value."\n"; - } else { - if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); - // It's mapped - if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; } - $string = $spaces.$key.': '.$value."\n"; - } - return $string; - } - - /** - * Creates a literal block for dumping - * @access private - * @return string - * @param $value - * @param $indent int The value of the indent - */ - private function _doLiteralBlock($value,$indent) { - if (strpos($value, "\n") === false && strpos($value, "'") === false) { - return sprintf ("'%s'", $value); - } - if (strpos($value, "\n") === false && strpos($value, '"') === false) { - return sprintf ('"%s"', $value); - } - $exploded = explode("\n",$value); - $newValue = '|'; - $indent += $this->_dumpIndent; - $spaces = str_repeat(' ',$indent); - foreach ($exploded as $line) { - $newValue .= "\n" . $spaces . trim($line); - } - return $newValue; - } - - /** - * Folds a string of text, if necessary - * @access private - * @return string - * @param $value The string you wish to fold - */ - private function _doFolding($value,$indent) { - // Don't do anything if wordwrap is set to 0 - - if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) { - $indent += $this->_dumpIndent; - $indent = str_repeat(' ',$indent); - $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent"); - $value = ">\n".$indent.$wrapped; - } else { - if ($this->setting_dump_force_quotes && is_string ($value)) - $value = '"' . $value . '"'; - } - - - return $value; - } - -// LOADING FUNCTIONS - - private function __load($input) { - $Source = $this->loadFromSource($input); - return $this->loadWithSource($Source); - } - - private function __loadString($input) { - $Source = $this->loadFromString($input); - return $this->loadWithSource($Source); - } - - private function loadWithSource($Source) { - if (empty ($Source)) return array(); - if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) { - $array = syck_load (implode ('', $Source)); - return is_array($array) ? $array : array(); - } - - $this->path = array(); - $this->result = array(); - - $cnt = count($Source); - for ($i = 0; $i < $cnt; $i++) { - $line = $Source[$i]; - - $this->indent = strlen($line) - strlen(ltrim($line)); - $tempPath = $this->getParentPathByIndent($this->indent); - $line = self::stripIndent($line, $this->indent); - if (self::isComment($line)) continue; - if (self::isEmpty($line)) continue; - $this->path = $tempPath; - - $literalBlockStyle = self::startsLiteralBlock($line); - if ($literalBlockStyle) { - $line = rtrim ($line, $literalBlockStyle . " \n"); - $literalBlock = ''; - $line .= $this->LiteralPlaceHolder; - - while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) { - $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle); - } - $i--; - } - - while (++$i < $cnt && self::greedilyNeedNextLine($line)) { - $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t"); - } - $i--; - - - - if (strpos ($line, '#')) { - if (strpos ($line, '"') === false && strpos ($line, "'") === false) - $line = preg_replace('/\s+#(.+)$/','',$line); - } - - $lineArray = $this->_parseLine($line); - - if ($literalBlockStyle) - $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock); - - $this->addArray($lineArray, $this->indent); - - foreach ($this->delayedPath as $indent => $delayedPath) - $this->path[$indent] = $delayedPath; - - $this->delayedPath = array(); - - } - return $this->result; - } - - private function loadFromSource ($input) { - if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) - return file($input); - - return $this->loadFromString($input); - } - - private function loadFromString ($input) { - $lines = explode("\n",$input); - foreach ($lines as $k => $_) { - $lines[$k] = rtrim ($_, "\r"); - } - return $lines; - } - - /** - * Parses YAML code and returns an array for a node - * @access private - * @return array - * @param string $line A line from the YAML file - */ - private function _parseLine($line) { - if (!$line) return array(); - $line = trim($line); - - if (!$line) return array(); - $array = array(); - - $group = $this->nodeContainsGroup($line); - if ($group) { - $this->addGroup($line, $group); - $line = $this->stripGroup ($line, $group); - } - - if ($this->startsMappedSequence($line)) - return $this->returnMappedSequence($line); - - if ($this->startsMappedValue($line)) - return $this->returnMappedValue($line); - - if ($this->isArrayElement($line)) - return $this->returnArrayElement($line); - - if ($this->isPlainArray($line)) - return $this->returnPlainArray($line); - - - return $this->returnKeyValuePair($line); - - } - - /** - * Finds the type of the passed value, returns the value as the new type. - * @access private - * @param string $value - * @return mixed - */ - private function _toType($value) { - if ($value === '') return null; - $first_character = $value[0]; - $last_character = substr($value, -1, 1); - - $is_quoted = false; - do { - if (!$value) break; - if ($first_character != '"' && $first_character != "'") break; - if ($last_character != '"' && $last_character != "'") break; - $is_quoted = true; - } while (0); - - if ($is_quoted) - return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); - - if (strpos($value, ' #') !== false) - $value = preg_replace('/\s+#(.+)$/','',$value); - - if ($first_character == '[' && $last_character == ']') { - // Take out strings sequences and mappings - $innerValue = trim(substr ($value, 1, -1)); - if ($innerValue === '') return array(); - $explode = $this->_inlineEscape($innerValue); - // Propagate value array - $value = array(); - foreach ($explode as $v) { - $value[] = $this->_toType($v); - } - return $value; - } - - if (strpos($value,': ')!==false && $first_character != '{') { - $array = explode(': ',$value); - $key = trim($array[0]); - array_shift($array); - $value = trim(implode(': ',$array)); - $value = $this->_toType($value); - return array($key => $value); - } - - if ($first_character == '{' && $last_character == '}') { - $innerValue = trim(substr ($value, 1, -1)); - if ($innerValue === '') return array(); - // Inline Mapping - // Take out strings sequences and mappings - $explode = $this->_inlineEscape($innerValue); - // Propagate value array - $array = array(); - foreach ($explode as $v) { - $SubArr = $this->_toType($v); - if (empty($SubArr)) continue; - if (is_array ($SubArr)) { - $array[key($SubArr)] = $SubArr[key($SubArr)]; continue; - } - $array[] = $SubArr; - } - return $array; - } - - if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { - return null; - } - - if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) { - $intvalue = (int)$value; - if ($intvalue != PHP_INT_MAX) - $value = $intvalue; - return $value; - } - - if (in_array($value, - array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) { - return true; - } - - if (in_array(strtolower($value), - array('false', 'off', '-', 'no', 'n'))) { - return false; - } - - if (is_numeric($value)) { - if ($value === '0') return 0; - if (trim ($value, 0) === $value) - $value = (float)$value; - return $value; - } - - return $value; - } - - /** - * Used in inlines to check for more inlines or quoted strings - * @access private - * @return array - */ - private function _inlineEscape($inline) { - // There's gotta be a cleaner way to do this... - // While pure sequences seem to be nesting just fine, - // pure mappings and mappings with sequences inside can't go very - // deep. This needs to be fixed. - - $seqs = array(); - $maps = array(); - $saved_strings = array(); - - // Check for strings - $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; - if (preg_match_all($regex,$inline,$strings)) { - $saved_strings = $strings[0]; - $inline = preg_replace($regex,'YAMLString',$inline); - } - unset($regex); - - $i = 0; - do { - - // Check for sequences - while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) { - $seqs[] = $matchseqs[0]; - $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); - } - - // Check for mappings - while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) { - $maps[] = $matchmaps[0]; - $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); - } - - if ($i++ >= 10) break; - - } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); - - $explode = explode(', ',$inline); - $stringi = 0; $i = 0; - - while (1) { - - // Re-add the sequences - if (!empty($seqs)) { - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLSeq') !== false) { - foreach ($seqs as $seqk => $seq) { - $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value); - $value = $explode[$key]; - } - } - } - } - - // Re-add the mappings - if (!empty($maps)) { - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLMap') !== false) { - foreach ($maps as $mapk => $map) { - $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value); - $value = $explode[$key]; - } - } - } - } - - - // Re-add the strings - if (!empty($saved_strings)) { - foreach ($explode as $key => $value) { - while (strpos($value,'YAMLString') !== false) { - $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1); - unset($saved_strings[$stringi]); - ++$stringi; - $value = $explode[$key]; - } - } - } - - $finished = true; - foreach ($explode as $key => $value) { - if (strpos($value,'YAMLSeq') !== false) { - $finished = false; break; - } - if (strpos($value,'YAMLMap') !== false) { - $finished = false; break; - } - if (strpos($value,'YAMLString') !== false) { - $finished = false; break; - } - } - if ($finished) break; - - $i++; - if ($i > 10) - break; // Prevent infinite loops. - } - - return $explode; - } - - private function literalBlockContinues ($line, $lineIndent) { - if (!trim($line)) return true; - if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true; - return false; - } - - private function referenceContentsByAlias ($alias) { - do { - if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; } - $groupPath = $this->SavedGroups[$alias]; - $value = $this->result; - foreach ($groupPath as $k) { - $value = $value[$k]; - } - } while (false); - return $value; - } - - private function addArrayInline ($array, $indent) { - $CommonGroupPath = $this->path; - if (empty ($array)) return false; - - foreach ($array as $k => $_) { - $this->addArray(array($k => $_), $indent); - $this->path = $CommonGroupPath; - } - return true; - } - - private function addArray ($incoming_data, $incoming_indent) { - - if (count ($incoming_data) > 1) - return $this->addArrayInline ($incoming_data, $incoming_indent); - - $key = key ($incoming_data); - $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; - - if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values. - if ($key || $key === '') { - $this->result[$key] = $value; - } else { - $this->result[] = $value; end ($this->result); $key = key ($this->result); - } - $this->path[$incoming_indent] = $key; - return; - } - - - - $history = array(); - // Unfolding inner array tree. - $history[] = $_arr = $this->result; - foreach ($this->path as $k) { - $history[] = $_arr = $_arr[$k]; - } - - if ($this->_containsGroupAlias) { - $value = $this->referenceContentsByAlias($this->_containsGroupAlias); - $this->_containsGroupAlias = false; - } - - - // Adding string or numeric key to the innermost level or $this->arr. - if (is_string($key) && $key == '<<') { - if (!is_array ($_arr)) { $_arr = array (); } - - $_arr = array_merge ($_arr, $value); - } else if ($key || $key === '') { - $_arr[$key] = $value; - } else { - if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } - else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } - } - - $reverse_path = array_reverse($this->path); - $reverse_history = array_reverse ($history); - $reverse_history[0] = $_arr; - $cnt = count($reverse_history) - 1; - for ($i = 0; $i < $cnt; $i++) { - $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i]; - } - $this->result = $reverse_history[$cnt]; - - $this->path[$incoming_indent] = $key; - - if ($this->_containsGroupAnchor) { - $this->SavedGroups[$this->_containsGroupAnchor] = $this->path; - if (is_array ($value)) { - $k = key ($value); - if (!is_int ($k)) { - $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k; - } - } - $this->_containsGroupAnchor = false; - } - - } - - private static function startsLiteralBlock ($line) { - $lastChar = substr (trim($line), -1); - if ($lastChar != '>' && $lastChar != '|') return false; - if ($lastChar == '|') return $lastChar; - // HTML tags should not be counted as literal blocks. - if (preg_match ('#<.*?>$#', $line)) return false; - return $lastChar; - } - - private static function greedilyNeedNextLine($line) { - $line = trim ($line); - if (!strlen($line)) return false; - if (substr ($line, -1, 1) == ']') return false; - if ($line[0] == '[') return true; - if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true; - return false; - } - - private function addLiteralLine ($literalBlock, $line, $literalBlockStyle) { - $line = self::stripIndent($line); - $line = rtrim ($line, "\r\n\t ") . "\n"; - if ($literalBlockStyle == '|') { - return $literalBlock . $line; - } - if (strlen($line) == 0) - return rtrim($literalBlock, ' ') . "\n"; - if ($line == "\n" && $literalBlockStyle == '>') { - return rtrim ($literalBlock, " \t") . "\n"; - } - if ($line != "\n") - $line = trim ($line, "\r\n ") . " "; - return $literalBlock . $line; - } - - function revertLiteralPlaceHolder ($lineArray, $literalBlock) { - foreach ($lineArray as $k => $_) { - if (is_array($_)) - $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock); - else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder) - $lineArray[$k] = rtrim ($literalBlock, " \r\n"); - } - return $lineArray; - } - - private static function stripIndent ($line, $indent = -1) { - if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line)); - return substr ($line, $indent); - } - - private function getParentPathByIndent ($indent) { - if ($indent == 0) return array(); - $linePath = $this->path; - do { - end($linePath); $lastIndentInParentPath = key($linePath); - if ($indent <= $lastIndentInParentPath) array_pop ($linePath); - } while ($indent <= $lastIndentInParentPath); - return $linePath; - } - - - private function clearBiggerPathValues ($indent) { - - - if ($indent == 0) $this->path = array(); - if (empty ($this->path)) return true; - - foreach ($this->path as $k => $_) { - if ($k > $indent) unset ($this->path[$k]); - } - - return true; - } - - - private static function isComment ($line) { - if (!$line) return false; - if ($line[0] == '#') return true; - if (trim($line, " \r\n\t") == '---') return true; - return false; - } - - private static function isEmpty ($line) { - return (trim ($line) === ''); - } - - - private function isArrayElement ($line) { - if (!$line) return false; - if ($line[0] != '-') return false; - if (strlen ($line) > 3) - if (substr($line,0,3) == '---') return false; - - return true; - } - - private function isHashElement ($line) { - return strpos($line, ':'); - } - - private function isLiteral ($line) { - if ($this->isArrayElement($line)) return false; - if ($this->isHashElement($line)) return false; - return true; - } - - - private function startsMappedSequence ($line) { - return ($line[0] == '-' && substr ($line, -1, 1) == ':'); - } - - private function returnMappedSequence ($line) { - $array = array(); - $key = trim(substr($line,1,-1)); - $array[$key] = array(); - $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key); - return array($array); - } - - private function returnMappedValue ($line) { - $array = array(); - $key = trim(substr($line,0,-1)); - $array[$key] = ''; - return $array; - } - - private function startsMappedValue ($line) { - return (substr ($line, -1, 1) == ':'); - } - - private function isPlainArray ($line) { - return ($line[0] == '[' && substr ($line, -1, 1) == ']'); - } - - private function returnPlainArray ($line) { - return $this->_toType($line); - } - - private function returnKeyValuePair ($line) { - $array = array(); - if (strpos ($line, ':')) { - // It's a key/value pair most likely - // If the key is in double quotes pull it out - if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) { - $value = trim(str_replace($matches[1],'',$line)); - $key = $matches[2]; - } else { - // Do some guesswork as to the key and the value - $explode = explode(':',$line); - $key = trim($explode[0]); - array_shift($explode); - $value = trim(implode(':',$explode)); - } - // Set the type of the value. Int, string, etc - $value = $this->_toType($value); - if (empty($key)) { - $array[] = $value; - } else { - $array[$key] = $value; - } - } - - return $array; - - } - - - private function returnArrayElement ($line) { - if (strlen($line) <= 1) return array(array()); // Weird %) - $array = array(); - $value = trim(substr($line,1)); - $value = $this->_toType($value); - $array[] = $value; - return $array; - } - - - private function nodeContainsGroup ($line) { - $symbolsForReference = 'A-z0-9_\-'; - if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-) - if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1]; - if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1]; - if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1]; - if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1]; - return false; - - } - - private function addGroup ($line, $group) { - if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1); - if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1); - //print_r ($this->path); - } - - private function stripGroup ($line, $group) { - $line = trim(str_replace($group, '', $line)); - return $line; - } -} - -// Enable use of Spyc from command line -// The syntax is the following: php spyc.php spyc.yaml - -define ('SPYC_FROM_COMMAND_LINE', false); - -do { - if (!SPYC_FROM_COMMAND_LINE) break; - if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break; - if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break; - $file = $argv[1]; - printf ("Spyc loading file: %s\n", $file); - print_r (spyc_load_file ($file)); -} while (0); diff --git a/thirdparty/spyc/spyc.yaml b/thirdparty/spyc/spyc.yaml deleted file mode 100644 index 4e512dd1f..000000000 --- a/thirdparty/spyc/spyc.yaml +++ /dev/null @@ -1,183 +0,0 @@ -# -# S P Y C -# a simple php yaml class -# -# authors: [vlad andersen (vlad.andersen@gmail.com), chris wanstrath (chris@ozmm.org)] -# websites: [http://www.yaml.org, http://spyc.sourceforge.net/] -# license: [MIT License, http://www.opensource.org/licenses/mit-license.php] -# copyright: (c) 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen -# -# spyc.yml - A file containing the YAML that Spyc understands. - ---- - -# Mappings - with proper types -String: Anyone's name, really. -Int: 13 -True: true -False: false -Zero: 0 -Null: NULL -Float: 5.34 - -# A sequence -- PHP Class -- Basic YAML Loader -- Very Basic YAML Dumper - -# A sequence of a sequence -- - - YAML is so easy to learn. - - Your config files will never be the same. - -# Sequence of mappings -- - cpu: 1.5ghz - ram: 1 gig - os : os x 10.4.1 - -# Mapped sequence -domains: - - yaml.org - - php.net - -# A sequence like this. -- program: Adium - platform: OS X - type: Chat Client - -# A folded block as a mapped value -no time: > - There isn't any time - for your tricks! - - Do you understand? - -# A literal block as a mapped value -some time: | - There is nothing but time - for your tricks. - -# Crazy combinations -databases: - - name: spartan - notes: - - Needs to be backed up - - Needs to be normalized - type: mysql - -# You can be a bit tricky -"if: you'd": like - -# Inline sequences -- [One, Two, Three, Four] - -# Nested Inline Sequences -- [One, [Two, And, Three], Four, Five] - -# Nested Nested Inline Sequences -- [This, [Is, Getting, [Ridiculous, Guys]], Seriously, [Show, Mercy]] - -# Inline mappings -- {name: chris, age: young, brand: lucky strike} - -# Nested inline mappings -- {name: mark, age: older than chris, brand: [marlboro, lucky strike]} - -# References -- they're shaky, but functional -dynamic languages: &DLANGS - - Perl - - Python - - PHP - - Ruby -compiled languages: &CLANGS - - C/C++ - - Java -all languages: - - *DLANGS - - *CLANGS - -# Added in .2.2: Escaped quotes -- you know, this shouldn't work. but it does. -- 'that''s my value.' -- 'again, that\'s my value.' -- "here's to \"quotes\", boss." - -# added in .2.3 -- {name: "Foo, Bar's", age: 20} - -# Added in .2.4: bug [ 1418193 ] Quote Values in Nested Arrays -- [a, ['1', "2"], b] - -# Added in .2.4: malformed YAML -all - javascripts: [dom1.js, dom.js] - -# Added in .2 -1040: Ooo, a numeric key! # And working comments? Wow! Colons in comments: a menace (0.3). - -hash_1: Hash #and a comment -hash_2: "Hash #and a comment" -"hash#3": "Hash (#) can appear in key too" - -float_test: 1.0 -float_test_with_quotes: '1.0' -float_inverse_test: 001 - -a_really_large_number: 115792089237316195423570985008687907853269984665640564039457584007913129639936 # 2^256 - -int array: [ 1, 2, 3 ] - -array on several lines: - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] - -morelesskey: "" - -array_of_zero: [0] -sophisticated_array_of_zero: {rx: {tx: [0]} } - -switches: - - { row: 0, col: 0, func: {tx: [0, 1]} } - -empty_sequence: [ ] -empty_hash: { } - -special_characters: "[{]]{{]]" - -asterisks: "*" - -empty_key: - : - key: value - -trailing_colon: "foo:" - -multiline_items: - - type: SomeItem - values: [blah, blah, blah, - blah] - ints: [2, 54, 12, - 2143] - -many_lines: | - A quick - fox - - - jumped - over - - - - - - a lazy - - - - dog - -# [Endloop] -endloop: | - Does this line in the end indeed make Spyc go to an infinite loop? \ No newline at end of file From 2f9bfae1f9f6bb2d33e3f979601e0abae243a7f6 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 2 Aug 2017 19:29:23 +0800 Subject: [PATCH 06/11] NEW Added MySQL SSL PDO Support Modified ConfigureFromEnv.php to parse SS_DATABASE_SSL variables (also added a bit of documentation) Modified PDOConnector.php to implement variables set in ConfigureFromEnv if exists Modified install files MySQLDatabaseConfigurationHelper and install.php5 to accept and implement SS_DATABASE_SSL variables set in _ss_environment.php TODO: Add documentation --- cli-script.php | 8 ++++++ conf/ConfigureFromEnv.php | 27 +++++++++++++++++++ .../MySQLDatabaseConfigurationHelper.php | 21 ++++++++++++++- dev/install/install.php5 | 14 ++++++++++ model/connect/PDOConnector.php | 16 +++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/cli-script.php b/cli-script.php index 48a87b38d..24e8526a2 100755 --- a/cli-script.php +++ b/cli-script.php @@ -91,6 +91,14 @@ define('SS_DATABASE_SERVER', 'localhost'); define('SS_DATABASE_USERNAME', ''); define('SS_DATABASE_PASSWORD', ''); define('SS_DATABASE_NAME', ''); + +/* SSL support for MySQLPDODatabase */ +/* +define('SS_DATABASE_CLASS', 'MySQLPDODatabase'); +define('SS_DATABASE_SSL_KEY', '/path/to/keyfile'); +define('SS_DATABASE_SSL_CERT', '/path/to/certfile'); +define('SS_DATABASE_SSL_CA', '/path/to/cafile');; +*/ -------------------------------------------------- Once you have done that, run 'composer install' or './framework/sake dev/build' to create diff --git a/conf/ConfigureFromEnv.php b/conf/ConfigureFromEnv.php index 2542150f0..3575f4636 100644 --- a/conf/ConfigureFromEnv.php +++ b/conf/ConfigureFromEnv.php @@ -20,6 +20,14 @@ * - SS_DATABASE_MEMORY: Use in-memory state if possible. Useful for testing, currently only * supported by the SQLite database adapter. * + * SSL Support (for MySQLPDODatabase) + * + * - SS_DATABASE_SSL_KEY: Path to SSL private key file + * - SS_DATABASE_SSL_CERT: Path to SSL certificate file + * - SS_DATABASE_SSL_CA: Path to SSL CA file + * - SS_DATABASE_SSL_CIPHER: Alternative cipher (defaults to DHE-RSA-AES256-SHA) + * + * * There is one more setting that is intended to be used by people who work on SilverStripe. * - SS_DATABASE_CHOOSE_NAME: Boolean/Int. If set, then the system will choose a default database name for you if * one isn't give in the $database variable. The database name will be "SS_" followed by the name of the folder @@ -116,6 +124,25 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) { // For SQlite3 memory databases (mainly for testing purposes) if(defined('SS_DATABASE_MEMORY')) $databaseConfig["memory"] = SS_DATABASE_MEMORY; + + // PDO MySQL SSL parameters + if(defined('SS_DATABASE_CLASS') && SS_DATABASE_CLASS === 'MySQLPDODatabase') { + + // add ssl parameters if these are defined + if( + defined('SS_DATABASE_SSL_KEY') && + defined('SS_DATABASE_SSL_CERT') && + defined('SS_DATABASE_SSL_CA') + ) { + + $databaseConfig['ssl_key'] = SS_DATABASE_SSL_KEY; + $databaseConfig['ssl_cert'] = SS_DATABASE_SSL_CERT; + $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; + $databaseConfig['ssl_cipher'] = defined('SS_DATABASE_SSL_CIPHER') ? SS_DATABASE_SSL_CIPHER : 'DHE-RSA-AES256-SHA'; + + } + } + } if(defined('SS_SEND_ALL_EMAILS_TO')) { diff --git a/dev/install/MySQLDatabaseConfigurationHelper.php b/dev/install/MySQLDatabaseConfigurationHelper.php index 5907eb4bb..86f7ff6e5 100644 --- a/dev/install/MySQLDatabaseConfigurationHelper.php +++ b/dev/install/MySQLDatabaseConfigurationHelper.php @@ -36,8 +36,27 @@ class MySQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper { } case 'MySQLPDODatabase': // May throw a PDOException if fails + + $ssl = null; + + if( + array_key_exists('ssl_key', $databaseConfig) && + array_key_exists('ssl_cert', $databaseConfig) && + array_key_exists('ssl_ca', $databaseConfig) && + array_key_exists('ssl_cipher', $databaseConfig)) { + + $ssl = array( + PDO::MYSQL_ATTR_SSL_KEY => $databaseConfig['ssl_key'], + PDO::MYSQL_ATTR_SSL_CERT => $databaseConfig['ssl_cert'], + PDO::MYSQL_ATTR_SSL_CA => $databaseConfig['ssl_ca'], + PDO::MYSQL_ATTR_SSL_CIPHER => $databaseConfig['ssl_cipher'], + ); + + + } + $conn = @new PDO('mysql:host='.$databaseConfig['server'], $databaseConfig['username'], - $databaseConfig['password']); + $databaseConfig['password'], $ssl); if($conn) { $conn->query("SET sql_mode = 'ANSI'"); return $conn; diff --git a/dev/install/install.php5 b/dev/install/install.php5 index 5df46ffbc..c83f4f5d7 100755 --- a/dev/install/install.php5 +++ b/dev/install/install.php5 @@ -132,6 +132,20 @@ if(isset($_REQUEST['db'])) { "database" => $_REQUEST['db'][$type]['database'], ); + if( + defined('SS_DATABASE_SSL_KEY') && + defined('SS_DATABASE_SSL_CERT') && + defined('SS_DATABASE_SSL_CA') + ) { + + $databaseConfig['ssl_key'] = SS_DATABASE_SSL_KEY; + $databaseConfig['ssl_cert'] = SS_DATABASE_SSL_CERT; + $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; + $databaseConfig['ssl_cipher'] = defined('SS_DATABASE_SSL_CIPHER') ? SS_DATABASE_SSL_CIPHER : 'DHE-RSA-AES256-SHA'; + + } + + } else { // Normal behaviour without the environment $databaseConfig = $_REQUEST['db'][$type]; diff --git a/model/connect/PDOConnector.php b/model/connect/PDOConnector.php index 4f8cf21bf..d7e1c00c5 100644 --- a/model/connect/PDOConnector.php +++ b/model/connect/PDOConnector.php @@ -159,6 +159,22 @@ class PDOConnector extends DBConnector { $options = array(); if($parameters['driver'] == 'mysql') { $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $charset . ' COLLATE ' . $connCollation; + + // Set SSL options from mysite/_config.php if they exist + if( + array_key_exists('ssl_key', $parameters) && + array_key_exists('ssl_cert', $parameters) && + array_key_exists('ssl_ca', $parameters) && + array_key_exists('ssl_cipher', $parameters)) { + + $options[PDO::MYSQL_ATTR_SSL_KEY] = $parameters['ssl_key']; + $options[PDO::MYSQL_ATTR_SSL_CERT] =$parameters['ssl_cert']; + $options[PDO::MYSQL_ATTR_SSL_CA] = $parameters['ssl_ca']; + $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher']; + + } + + } if(self::is_emulate_prepare()) { $options[PDO::ATTR_EMULATE_PREPARES] = true; From a3678c73b9061583633a477c34cb9202bf906e28 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 3 Aug 2017 12:53:27 +0800 Subject: [PATCH 07/11] Refactor code to decouple SSL feature from MySQL PDO --- conf/ConfigureFromEnv.php | 35 +++++++++++-------- .../MySQLDatabaseConfigurationHelper.php | 14 +++++--- dev/install/install.php5 | 14 +++++--- model/connect/PDOConnector.php | 23 ++++++++---- 4 files changed, 56 insertions(+), 30 deletions(-) diff --git a/conf/ConfigureFromEnv.php b/conf/ConfigureFromEnv.php index 3575f4636..cf86b1a5a 100644 --- a/conf/ConfigureFromEnv.php +++ b/conf/ConfigureFromEnv.php @@ -25,7 +25,7 @@ * - SS_DATABASE_SSL_KEY: Path to SSL private key file * - SS_DATABASE_SSL_CERT: Path to SSL certificate file * - SS_DATABASE_SSL_CA: Path to SSL CA file - * - SS_DATABASE_SSL_CIPHER: Alternative cipher (defaults to DHE-RSA-AES256-SHA) + * - SS_DATABASE_SSL_CIPHER: Override default cipher (defaults are set per database connector) * * * There is one more setting that is intended to be used by people who work on SilverStripe. @@ -125,24 +125,29 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) { if(defined('SS_DATABASE_MEMORY')) $databaseConfig["memory"] = SS_DATABASE_MEMORY; - // PDO MySQL SSL parameters - if(defined('SS_DATABASE_CLASS') && SS_DATABASE_CLASS === 'MySQLPDODatabase') { + // Add ssl parameters to databaseConfig if these are defined + if( + defined('SS_DATABASE_SSL_KEY') && + defined('SS_DATABASE_SSL_CERT') + ) { - // add ssl parameters if these are defined - if( - defined('SS_DATABASE_SSL_KEY') && - defined('SS_DATABASE_SSL_CERT') && - defined('SS_DATABASE_SSL_CA') - ) { + $databaseConfig['ssl_key'] = SS_DATABASE_SSL_KEY; + $databaseConfig['ssl_cert'] = SS_DATABASE_SSL_CERT; - $databaseConfig['ssl_key'] = SS_DATABASE_SSL_KEY; - $databaseConfig['ssl_cert'] = SS_DATABASE_SSL_CERT; - $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; - $databaseConfig['ssl_cipher'] = defined('SS_DATABASE_SSL_CIPHER') ? SS_DATABASE_SSL_CIPHER : 'DHE-RSA-AES256-SHA'; - - } } + // Some databases do not require a CA so this is optional + if(defined('SS_DATABASE_SSL_CA')) { + $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; + } + + // Cipher defaults should be set per connector + if(defined('SS_DATABASE_SSL_CIPHER')) { + $databaseConfig['ssl_cipher'] = SS_DATABASE_SSL_CIPHER; + } + + + } if(defined('SS_SEND_ALL_EMAILS_TO')) { diff --git a/dev/install/MySQLDatabaseConfigurationHelper.php b/dev/install/MySQLDatabaseConfigurationHelper.php index 86f7ff6e5..8815fcc03 100644 --- a/dev/install/MySQLDatabaseConfigurationHelper.php +++ b/dev/install/MySQLDatabaseConfigurationHelper.php @@ -37,21 +37,25 @@ class MySQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper { case 'MySQLPDODatabase': // May throw a PDOException if fails + // Set SSL parameters $ssl = null; + $defaultCipher = 'DHE-RSA-AES256-SHA'; if( array_key_exists('ssl_key', $databaseConfig) && - array_key_exists('ssl_cert', $databaseConfig) && - array_key_exists('ssl_ca', $databaseConfig) && - array_key_exists('ssl_cipher', $databaseConfig)) { + array_key_exists('ssl_cert', $databaseConfig)) { $ssl = array( PDO::MYSQL_ATTR_SSL_KEY => $databaseConfig['ssl_key'], PDO::MYSQL_ATTR_SSL_CERT => $databaseConfig['ssl_cert'], - PDO::MYSQL_ATTR_SSL_CA => $databaseConfig['ssl_ca'], - PDO::MYSQL_ATTR_SSL_CIPHER => $databaseConfig['ssl_cipher'], ); + if(array_key_exists('ssl_ca', $databaseConfig)) { + $ssl[PDO::MYSQL_ATTR_SSL_CA] = $databaseConfig['ssl_ca']; + } + + // use default cipher if not provided + $ssl[PDO::MYSQL_ATTR_SSL_CA] = array_key_exists('ssl_ca', $databaseConfig) ? $databaseConfig['ssl_ca'] : $defaultCipher; } diff --git a/dev/install/install.php5 b/dev/install/install.php5 index c83f4f5d7..795383727 100755 --- a/dev/install/install.php5 +++ b/dev/install/install.php5 @@ -132,19 +132,25 @@ if(isset($_REQUEST['db'])) { "database" => $_REQUEST['db'][$type]['database'], ); + // Set SSL parameters if they exist if( defined('SS_DATABASE_SSL_KEY') && - defined('SS_DATABASE_SSL_CERT') && - defined('SS_DATABASE_SSL_CA') + defined('SS_DATABASE_SSL_CERT') ) { $databaseConfig['ssl_key'] = SS_DATABASE_SSL_KEY; $databaseConfig['ssl_cert'] = SS_DATABASE_SSL_CERT; - $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; - $databaseConfig['ssl_cipher'] = defined('SS_DATABASE_SSL_CIPHER') ? SS_DATABASE_SSL_CIPHER : 'DHE-RSA-AES256-SHA'; } + if(defined('SS_DATABASE_SSL_CA')) { + $databaseConfig['ssl_ca'] = SS_DATABASE_SSL_CA; + } + + if(defined('SS_DATABASE_SSL_CIPHER')) { + $databaseConfig['ssl_cipher'] = SS_DATABASE_SSL_CIPHER; + } + } else { // Normal behaviour without the environment diff --git a/model/connect/PDOConnector.php b/model/connect/PDOConnector.php index d7e1c00c5..fd5b6d3b8 100644 --- a/model/connect/PDOConnector.php +++ b/model/connect/PDOConnector.php @@ -15,6 +15,14 @@ class PDOConnector extends DBConnector { */ private static $emulate_prepare = false; + /** + * Default strong SSL cipher to be used + * + * @config + * @var boolean + */ + private static $ssl_cipher_default = 'DHE-RSA-AES256-SHA'; + /** * The PDO connection instance * @@ -160,17 +168,20 @@ class PDOConnector extends DBConnector { if($parameters['driver'] == 'mysql') { $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $charset . ' COLLATE ' . $connCollation; - // Set SSL options from mysite/_config.php if they exist + // Set SSL options if they are defined if( array_key_exists('ssl_key', $parameters) && - array_key_exists('ssl_cert', $parameters) && - array_key_exists('ssl_ca', $parameters) && - array_key_exists('ssl_cipher', $parameters)) { + array_key_exists('ssl_cert', $parameters)) { $options[PDO::MYSQL_ATTR_SSL_KEY] = $parameters['ssl_key']; - $options[PDO::MYSQL_ATTR_SSL_CERT] =$parameters['ssl_cert']; + $options[PDO::MYSQL_ATTR_SSL_CERT] = $parameters['ssl_cert']; + + if(array_key_exists('ssl_ca', $parameters)) { $options[PDO::MYSQL_ATTR_SSL_CA] = $parameters['ssl_ca']; - $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher']; + } + + // use default cipher if not provided + $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher'] ?: $this->config()->ssl_cipher_default; } From 8577ad128059f4c508f03df4e5566c09fe161be5 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 3 Aug 2017 19:37:01 +0800 Subject: [PATCH 08/11] NEW Added SSL support for MySQLi Connector (fixes #7242) Modified MySQLiConnector.php to parse SSL environment variables Modifed MySQLDatabaseConfigurationHelper.php to check SSL variables when testing initial connection Minor: Modified PDOConnector.php to change typo TODO: Add Documentation --- .../MySQLDatabaseConfigurationHelper.php | 33 +++++++++++-- model/connect/MySQLiConnector.php | 48 +++++++++++++------ model/connect/PDOConnector.php | 4 +- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/dev/install/MySQLDatabaseConfigurationHelper.php b/dev/install/MySQLDatabaseConfigurationHelper.php index 8815fcc03..807f1d0dd 100644 --- a/dev/install/MySQLDatabaseConfigurationHelper.php +++ b/dev/install/MySQLDatabaseConfigurationHelper.php @@ -18,13 +18,39 @@ class MySQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper { * @param string $error Error message passed by value * @return mixed|null Either the connection object, or null if error */ + protected function createConnection($databaseConfig, &$error) { $error = null; try { switch($databaseConfig['type']) { case 'MySQLDatabase': - $conn = @new MySQLi($databaseConfig['server'], $databaseConfig['username'], - $databaseConfig['password']); + + + $conn = mysqli_init(); + + // Set SSL parameters if they exist. All parameters are required. + if( + array_key_exists('ssl_key', $databaseConfig) && + array_key_exists('ssl_cert', $databaseConfig) && + array_key_exists('ssl_ca', $databaseConfig)) { + + $conn->ssl_set( + $databaseConfig['ssl_key'], + $databaseConfig['ssl_cert'], + $databaseConfig['ssl_ca'], + dirname($databaseConfig['ssl_ca']), + array_key_exists('ssl_cipher', $databaseConfig) ? $databaseConfig['ssl_cipher'] : Config::inst()->get('MySQLiConnector', 'ssl_cipher_default') + ); + + } + + + @$conn->real_connect( + $databaseConfig['server'], + $databaseConfig['username'], + $databaseConfig['password'] + ); + if($conn && empty($conn->connect_errno)) { $conn->query("SET sql_mode = 'ANSI'"); return $conn; @@ -39,7 +65,6 @@ class MySQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper { // Set SSL parameters $ssl = null; - $defaultCipher = 'DHE-RSA-AES256-SHA'; if( array_key_exists('ssl_key', $databaseConfig) && @@ -55,7 +80,7 @@ class MySQLDatabaseConfigurationHelper implements DatabaseConfigurationHelper { } // use default cipher if not provided - $ssl[PDO::MYSQL_ATTR_SSL_CA] = array_key_exists('ssl_ca', $databaseConfig) ? $databaseConfig['ssl_ca'] : $defaultCipher; + $ssl[PDO::MYSQL_ATTR_SSL_CA] = array_key_exists('ssl_ca', $databaseConfig) ? $databaseConfig['ssl_ca'] : Config::inst()->get('PDOConnector', 'ssl_cipher_default'); } diff --git a/model/connect/MySQLiConnector.php b/model/connect/MySQLiConnector.php index f56a6649b..13af37003 100644 --- a/model/connect/MySQLiConnector.php +++ b/model/connect/MySQLiConnector.php @@ -7,6 +7,14 @@ */ class MySQLiConnector extends DBConnector { + /** + * Default strong SSL cipher to be used + * + * @config + * @var string + */ + private static $ssl_cipher_default = 'DHE-RSA-AES256-SHA'; + /** * Connection to the MySQL database * @@ -60,23 +68,35 @@ class MySQLiConnector extends DBConnector { $connCharset = Config::inst()->get('MySQLDatabase', 'connection_charset'); $connCollation = Config::inst()->get('MySQLDatabase', 'connection_collation'); - if(!empty($parameters['port'])) { - $this->dbConn = new MySQLi( - $parameters['server'], - $parameters['username'], - $parameters['password'], - $selectedDB, - $parameters['port'] - ); - } else { - $this->dbConn = new MySQLi( - $parameters['server'], - $parameters['username'], - $parameters['password'], - $selectedDB + $this->dbConn = mysqli_init(); + + // Set SSL parameters if they exist. All parameters are required. + + if( + array_key_exists('ssl_key', $parameters) && + array_key_exists('ssl_cert', $parameters) && + array_key_exists('ssl_ca', $parameters)) { + + $this->dbConn->ssl_set( + $parameters['ssl_key'], + $parameters['ssl_cert'], + $parameters['ssl_ca'], + dirname($parameters['ssl_ca']), + array_key_exists('ssl_cipher', $parameters) ? $parameters['ssl_cipher'] : Config::inst()->get('MySQLiConnector', 'ssl_cipher_default') ); + } + + $this->dbConn->real_connect( + $parameters['server'], + $parameters['username'], + $parameters['password'], + $selectedDB, + !empty($parameters['port']) ? $parameters['port'] : ini_get("mysqli.default_port") + + ); + if ($this->dbConn->connect_error) { $this->databaseError("Couldn't connect to MySQL database | " . $this->dbConn->connect_error); } diff --git a/model/connect/PDOConnector.php b/model/connect/PDOConnector.php index fd5b6d3b8..8b36a52e5 100644 --- a/model/connect/PDOConnector.php +++ b/model/connect/PDOConnector.php @@ -19,7 +19,7 @@ class PDOConnector extends DBConnector { * Default strong SSL cipher to be used * * @config - * @var boolean + * @var string */ private static $ssl_cipher_default = 'DHE-RSA-AES256-SHA'; @@ -181,7 +181,7 @@ class PDOConnector extends DBConnector { } // use default cipher if not provided - $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher'] ?: $this->config()->ssl_cipher_default; + $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher'] ?: Config::inst()->get('PDOConnector', 'ssl_cipher_default'); } From 59b28f7d5bcefd477766611a99643f121af3dc56 Mon Sep 17 00:00:00 2001 From: Russell Michell Date: Mon, 7 Aug 2017 10:55:38 +1200 Subject: [PATCH 09/11] FIX: Fixes #7181 to config system for userland config of node display limits. --- forms/TreeDropdownField.php | 10 +++++++++- model/Hierarchy.php | 6 ++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/forms/TreeDropdownField.php b/forms/TreeDropdownField.php index d3a7cbc8c..91200a27a 100644 --- a/forms/TreeDropdownField.php +++ b/forms/TreeDropdownField.php @@ -50,6 +50,13 @@ class TreeDropdownField extends FormField { 'tree' ); + /** + * @config + * @var int + * @see {@link Hierarchy::$node_threshold_total}. + */ + private static $node_threshold_total = 30; + /** * @ignore */ @@ -303,7 +310,8 @@ class TreeDropdownField extends FormField { if ($this->filterCallback || $this->search != "" ) $obj->setMarkingFilterFunction(array($this, "filterMarking")); - $obj->markPartialTree($nodeCountThreshold = 30, $context = null, + $nodeCountThreshold = Config::inst()->get('TreeDropdownField', 'node_threshold_total'); + $obj->markPartialTree($nodeCountThreshold, $context = null, $this->childrenMethod, $this->numChildrenMethod); // allow to pass values to be selected within the ajax request diff --git a/model/Hierarchy.php b/model/Hierarchy.php index c42b94be5..7c8b71bd5 100644 --- a/model/Hierarchy.php +++ b/model/Hierarchy.php @@ -218,10 +218,12 @@ class Hierarchy extends DataExtension { * @param int $nodeCountThreshold See {@link getChildrenAsUL()} * @return int The actual number of nodes marked. */ - public function markPartialTree($nodeCountThreshold = 30, $context = null, + public function markPartialTree($nodeCountThreshold = null, $context = null, $childrenMethod = "AllChildrenIncludingDeleted", $numChildrenMethod = "numChildren") { - if(!is_numeric($nodeCountThreshold)) $nodeCountThreshold = 30; + if(!is_numeric($nodeCountThreshold)) { + $nodeCountThreshold = Config::inst()->get('Hierarchy', 'node_threshold_total'); + } $this->markedNodes = array($this->owner->ID => $this->owner); $this->owner->markUnexpanded(); From 10bf2286a5a507e994ee6251c087d030da7884a4 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 7 Aug 2017 16:26:37 +0800 Subject: [PATCH 10/11] Add SSL Documentation to docs (fixes #7253) --- .../How_To/MySQL_SSL_Support.md | 169 ++++++++++++++++++ .../03_Environment_Management.md | 35 +++- 2 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 docs/en/00_Getting_Started/01_Installation/How_To/MySQL_SSL_Support.md diff --git a/docs/en/00_Getting_Started/01_Installation/How_To/MySQL_SSL_Support.md b/docs/en/00_Getting_Started/01_Installation/How_To/MySQL_SSL_Support.md new file mode 100644 index 000000000..c47e358a6 --- /dev/null +++ b/docs/en/00_Getting_Started/01_Installation/How_To/MySQL_SSL_Support.md @@ -0,0 +1,169 @@ +title: MySQL SSL Support +summary: Setting up MySQL SSL certificates to work with Silverstripe + +# MySQL SSL Support: Why do I need it? + +In a typical Silverstripe set up, you will only need to use a single host to function as the web server, email server, database server, among others. + +In some cases, however, you may be required to connect to a database on a remote host. Connecting to a remote host without SSL encryption exposes your data to [packet sniffing](http://www.linuxjournal.com/content/packet-sniffing-basics) and may compromise the security of your Silverstripe instance. + +This article demonstrates how to generate SSL certificates using MySQL and implementing them in Silverstripe. + +
+This article assumes that you have `MySQL` and `OpenSSL` installed. +
+ + +## Generating Certificates + +There are three components to an SSL certificate implementation. The first two components are the ***private key***, and the ***public certificate***, which are mathematically-generated, symetrical pieces of the puzzle that allow [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) to work. The third component is the [Certificate Authority (CA) certificate](https://en.wikipedia.org/wiki/Certificate_authority) that signs the pubic key to prove its validity. + +In the case of MySQL, we will need to generate three sets of certificates, namely: + +- the CA key and certificate +- the server key and certificate +- the client key and certificate + +We also need to sign the certificates with our generated CA. + +The commands below illustrate how to do so on your MySQL host. + +
+The following commands will work on Linux/Unix based servers. For other servers such as windows, refer to the [MySQL documentation](https://dev.mysql.com/doc/refman/5.7/en/creating-ssl-files-using-openssl.html) +
+ + + :::bash + + # Create directory + sudo mkdir ssl + cd ssl + + # Generate CA key and CA cert + sudo openssl genrsa 2048 | sudo tee -a ca-key.pem + sudo openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem + + # Generate SERVER key and server certificate signing request + # IMPORTANT: the common name of the certificate should match the domain name of your host! + sudo openssl rsa -in server-key.pem -out server-key.pem + sudo openssl req -newkey rsa:2048 -days 365000 -nodes -keyout server-key.pem -out server-req.pem + + # Generate and sign SERVER certificate + sudo openssl x509 -req -in server-req.pem -days 365000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem + + # Generate CLIENT key and certificate signing request + sudo openssl rsa -in client-key.pem -out client-key.pem + sudo openssl req -newkey rsa:2048 -days 365000 -nodes -keyout client-key.pem -out client-req.pem + + # Generate and sign CLIENT certificate + sudo openssl x509 -req -in client-req.pem -days 365000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem + + # Verify validity of generated certificates + sudo openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem + +
+After generating the certificates, make sure to set the correct permissions to prevent unauthorized access to your keys! + +It is critical that the key files (files ending in *key.pem) are kept secret. Once these files are exposed, you will need to regenerate the certificates to prevent exposing your data traffic. +
+ + :::bash + # Set permissions readonly permissions and change owner to root + sudo chown root:root *.pem + sudo chmod 440 *.pem + + # Server certificates need to be readable by mysql + sudo chgrp mysql server*.pem + sudo mv *.pem /etc/mysql/ssl + + +## Setting up MySQL to use SSL certificates + +
+For Debian/Ubuntu instances, the configuration file is usually in `/etc/mysql/my.cnf`. Refer to your MySQL manual for more information +
+ +We must edit the MySQL configuration to use the newly generated certificates. + +Edit your MySQL configuration file as follows. + + + [mysqld] + ... + ssl-ca=/etc/mysql/ca-cert.pem + ssl-cert=/etc/mysql/server-cert.pem + ssl-key=/etc/mysql/server-key.pem + + # IMPORTANT! When enabling MySQL remote connections, make sure to take adequate steps to secure your machine from unathorized access! + bind-address=0.0.0.0 + +
+Enabling remote connections to your MySQL instance introduces various security risks. Make sure to take appropriate steps to secure your instance by using a strong password, disabling MySQL root access, and using a firewall to only accept qualified hosts, for example. +
+ +Make sure to restart your MySQL instance to reflect the changes. + + :::bash + sudo service mysql restart + + +## Setting up Silverstripe to connect to MySQL + +Now that we have successfully setup the SSL your MySQL host, we now need to configure Silverstripe to use the certificates. + +### Copying SSL Certificates + +First we need to copy the client certificate files to the Silverstripe instance. You will need to copy: + +- `client-key.pem` +- `client-cert.pem` +- `ca-cert.pem` + +
+Make sure to only copy `client-key.pem`, `client-cert.pem`, and `ca-cert.pem` to avoid leaking your credentials! +
+ +On your Silverstripe instance: + + :::bash + # Secure copy over SSH via rsync command. You may use an alternative method if desired. + rsync -avP user@db1.example.com:/path/to/client/certs /path/to/secure/folder + + # Depending on your web server configuration, allow web server to read to SSL files + sudo chown -R www-data:www-data /path/to/secure/folder + sudo chmod 750 /path/to/secure/folder + sudo chmod 400 /path/to/secure/folder/* + +### Setting up _ss_environment.php to use SSL certificates + +
+`SS_DATABASE_SERVER does not accept IP-based hostnames. Also, if the domain name of the host does not match the common name you used to generate the server certificate, you will get an `SSL certificate mismatch error`. +
+ +Add or edit your `_ss_environment.php` configuration file. (See [Environment Management](/getting_started/environment_management) for more information.) + + :::php + '); + + // These define the paths to the SSL key, certificate, and CA certificate bundle. + define('SS_DATABASE_SSL_KEY', '/home/newdrafts/mysqlssltest/client-key.pem'); + define('SS_DATABASE_SSL_CERT', '/home/newdrafts/mysqlssltest/client-cert.pem'); + define('SS_DATABASE_SSL_CA', '/home/newdrafts/mysqlssltest/ca- cert.pem'); + + // When using SSL connections, you also need to supply a username and password to override the default settings + define('SS_DEFAULT_ADMIN_USERNAME', 'username'); + define('SS_DEFAULT_ADMIN_PASSWORD', 'password'); + + +When running the installer, make sure to check on the `Use _ss_environment file for configuration` option under the `Database Configuration` section to use the environment file. + +## Conclusion + +That's it! We hope that this article was able to help you configure your remote MySQL SSL secure database connection. \ No newline at end of file diff --git a/docs/en/00_Getting_Started/03_Environment_Management.md b/docs/en/00_Getting_Started/03_Environment_Management.md index feb87ffed..d227f060e 100644 --- a/docs/en/00_Getting_Started/03_Environment_Management.md +++ b/docs/en/00_Getting_Started/03_Environment_Management.md @@ -102,6 +102,35 @@ This is my `_ss_environment.php` file. I have it placed in `/var`, as each of th global $_FILE_TO_URL_MAPPING; $_FILE_TO_URL_MAPPING['/var/www'] = 'http://simon.geek.nz'; +### Example settings to enable Database SSL + +In some circumstances, like connecting to a database on a remote host for example, you may wish to enable SSL encryption to ensure the protection of sensitive information and database access credentials. The code below illustrates how to do so. + +
+SSL database connections are supported for `MySQLDatabase` and `MySQLPDODatabase` as of the moment. +
+ + :::php + '); + define('SS_DATABASE_PASSWORD', ''); + + // These define the paths to the SSL key, certificate, and CA certificate bundle. + define('SS_DATABASE_SSL_KEY', '/path/to/ssl/folder/client-key.pem'); + define('SS_DATABASE_SSL_CERT', '/path/to/ssl/folder/client-cert.pem'); + define('SS_DATABASE_SSL_CA', '/path/to/ssl/folder/ca-cert.pem'); + + // When using SSL connections, you also need to supply a username and password to override the default settings + define('SS_DEFAULT_ADMIN_USERNAME', 'username'); + define('SS_DEFAULT_ADMIN_PASSWORD', 'password'); + + +When running the installer, make sure to check on the `Use _ss_environment file for configuration` option under the `Database Configuration` section to use the environment file. + ## Available Constants | Name | Description | @@ -125,4 +154,8 @@ This is my `_ss_environment.php` file. I have it placed in `/var`, as each of th | `SS_SEND_ALL_EMAILS_TO`| If you define this constant, all emails will be redirected to this address.| | `SS_SEND_ALL_EMAILS_FROM`| If you define this constant, all emails will be sent from this address.| | `SS_ERROR_LOG` | Relative path to the log file. | -| `SS_CONFIGSTATICMANIFEST` | Set to `SS_ConfigStaticManifest_Reflection` to use the Silverstripe 4 Reflection config manifest (speed improvement during dev/build and ?flush) | \ No newline at end of file +| `SS_CONFIGSTATICMANIFEST` | Set to `SS_ConfigStaticManifest_Reflection` to use the Silverstripe 4 Reflection config manifest (speed improvement during dev/build and ?flush) | +| `SS_DATABASE_SSL_KEY` | Absolute path to SSL key file | +| `SS_DATABASE_SSL_CERT` | Absolute path to SSL certificate file | +| `SS_DATABASE_SSL_CA` | Absolute path to SSL Certificate Authority bundle file | +| `SS_DATABASE_SSL_CIPHER` | Optional setting for custom SSL cipher | From 1a4a006d09e4397c3126fcf32c61692f90834b8a Mon Sep 17 00:00:00 2001 From: John Date: Tue, 8 Aug 2017 17:54:30 +0800 Subject: [PATCH 11/11] FIX: PDOConnector ssl_cipher bug fixes #7258 --- model/connect/PDOConnector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/connect/PDOConnector.php b/model/connect/PDOConnector.php index 8b36a52e5..699959194 100644 --- a/model/connect/PDOConnector.php +++ b/model/connect/PDOConnector.php @@ -181,7 +181,7 @@ class PDOConnector extends DBConnector { } // use default cipher if not provided - $options[PDO::MYSQL_ATTR_SSL_CIPHER] = $parameters['ssl_cipher'] ?: Config::inst()->get('PDOConnector', 'ssl_cipher_default'); + $options[PDO::MYSQL_ATTR_SSL_CIPHER] = array_key_exists('ssl_cipher', $parameters) ? $parameters['ssl_cipher'] : Config::inst()->get('PDOConnector', 'ssl_cipher_default'); }