From 40bf94532278d29bd58ebe161870cfe0784d8a7e Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Mon, 3 Apr 2017 21:05:25 +0100 Subject: [PATCH 01/12] NEW: PHP 7 compatibility This patch introduces PHP 7 compatability without breaking semver by adding DBInt and DBFloat classes, with Int/Float classes that are only loaded into PHP 5 environments --- .travis.yml | 8 ++++++-- _config/database.yml | 4 ++++ composer.json | 2 +- core/Core.php | 3 +++ core/Diff.php | 21 ++++++++------------- model/connect/DBSchemaManager.php | 4 ++-- model/fieldtypes/Bigint.php | 2 +- model/fieldtypes/{Float.php => DBFloat.php} | 2 +- model/fieldtypes/{Int.php => DBInt.php} | 3 +-- model/fieldtypes/Double.php | 2 +- model/fieldtypes/ForeignKey.php | 2 +- model/fieldtypes/PrimaryKey.php | 2 +- model/fieldtypes/compat/Float.php | 6 ++++++ model/fieldtypes/compat/Int.php | 6 ++++++ model/fieldtypes/compat/_manifest_exclude | 0 model/fieldtypes/compat/autoload.php | 17 +++++++++++++++++ tests/model/DBFieldTest.php | 19 +++++++++++++++++++ tests/model/VersionedTest.php | 4 ++-- view/SSViewer.php | 2 +- view/ViewableData.php | 2 +- 20 files changed, 82 insertions(+), 29 deletions(-) rename model/fieldtypes/{Float.php => DBFloat.php} (97%) rename model/fieldtypes/{Int.php => DBInt.php} (97%) create mode 100644 model/fieldtypes/compat/Float.php create mode 100644 model/fieldtypes/compat/Int.php create mode 100644 model/fieldtypes/compat/_manifest_exclude create mode 100644 model/fieldtypes/compat/autoload.php diff --git a/.travis.yml b/.travis.yml index 1e9dc562e..34534a945 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,11 +17,15 @@ matrix: env: DB=SQLITE - php: 5.6 env: DB=MYSQL PDO=1 + - php: 7.0 + env: DB=MYSQL + - php: 7.1 + env: DB=MYSQL PDO=1 - php: 5.6 env: DB=MYSQL BEHAT_TEST=1 - - php: 5.6 + - php: 7.0 env: DB=MYSQL CMS_TEST=1 - - php: 5.6 + - php: 7.0 env: DB=MYSQL BEHAT_TEST=1 CMS_TEST=1 before_script: diff --git a/_config/database.yml b/_config/database.yml index 86cc2e927..2bb8e1c85 100644 --- a/_config/database.yml +++ b/_config/database.yml @@ -20,3 +20,7 @@ Injector: PDOConnector: class: 'PDOConnector' type: prototype + Int: + class: DBInt + Float: + class: DBFloat diff --git a/composer.json b/composer.json index 37a4913f9..c6578bff7 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=5.3.3,<7", + "php": ">= 5.3.3, <7.2", "composer/installers": "~1.0" }, "require-dev": { diff --git a/core/Core.php b/core/Core.php index 756941a1c..8d6efe463 100644 --- a/core/Core.php +++ b/core/Core.php @@ -112,6 +112,9 @@ if(file_exists(BASE_PATH . '/vendor/autoload.php')) { require_once BASE_PATH . '/vendor/autoload.php'; } +// Int/Float autoloader for PHP5.6 backwards-compatability +require_once(BASE_PATH . '/framework/model/fieldtypes/compat/autoload.php'); + // Now that the class manifest is up, load the static configuration $configManifest = new SS_ConfigStaticManifest(BASE_PATH, false, $flush); Config::inst()->pushConfigStaticManifest($configManifest); diff --git a/core/Diff.php b/core/Diff.php index d76fd379e..dc4a05070 100644 --- a/core/Diff.php +++ b/core/Diff.php @@ -14,12 +14,7 @@ // You may copy this code freely under the conditions of the GPL. // -// FIXME: possibly remove assert()'s for production version? - -// PHP3 does not have assert() -/** - */ -define('USE_ASSERTS', function_exists('assert')); +define('USE_ASSERTS', true); /** * @package framework @@ -52,7 +47,7 @@ class _DiffOp { class _DiffOp_Copy extends _DiffOp { var $type = 'copy'; - public function _DiffOp_Copy ($orig, $final = false) { + public function __construct ($orig, $final = false) { if (!is_array($final)) $final = $orig; $this->orig = $orig; @@ -72,7 +67,7 @@ class _DiffOp_Copy extends _DiffOp { class _DiffOp_Delete extends _DiffOp { var $type = 'delete'; - public function _DiffOp_Delete ($lines) { + public function __construct ($lines) { $this->orig = $lines; $this->final = false; } @@ -90,7 +85,7 @@ class _DiffOp_Delete extends _DiffOp { class _DiffOp_Add extends _DiffOp { var $type = 'add'; - public function _DiffOp_Add ($lines) { + public function __construct ($lines) { $this->final = $lines; $this->orig = false; } @@ -108,7 +103,7 @@ class _DiffOp_Add extends _DiffOp { class _DiffOp_Change extends _DiffOp { var $type = 'change'; - public function _DiffOp_Change ($orig, $final) { + public function __construct ($orig, $final) { $this->orig = $orig; $this->final = $final; } @@ -541,7 +536,7 @@ class Diff * (Typically these are lines from a file.) * @param $to_lines array An array of strings. */ - public function Diff($from_lines, $to_lines) { + public function __construct($from_lines, $to_lines) { $eng = new _DiffEngine; $this->edits = $eng->diff($from_lines, $to_lines); //$this->_check($from_lines, $to_lines); @@ -853,13 +848,13 @@ extends Diff * @param $mapped_to_lines array This array should * have the same number of elements as $to_lines. */ - public function MappedDiff($from_lines, $to_lines, + public function __construct($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) { assert(sizeof($from_lines) == sizeof($mapped_from_lines)); assert(sizeof($to_lines) == sizeof($mapped_to_lines)); - $this->Diff($mapped_from_lines, $mapped_to_lines); + parent::__construct($mapped_from_lines, $mapped_to_lines); $xi = $yi = 0; // Optimizing loop invariants: diff --git a/model/connect/DBSchemaManager.php b/model/connect/DBSchemaManager.php index ec75b5207..e7660ceb0 100644 --- a/model/connect/DBSchemaManager.php +++ b/model/connect/DBSchemaManager.php @@ -578,7 +578,7 @@ abstract class DBSchemaManager { $spec['parts']['name'] = $field; $spec_orig['parts']['name'] = $field; //Convert the $spec array into a database-specific string - $spec = $this->$spec['type']($spec['parts'], true); + $spec = $this->{$spec['type']}($spec['parts'], true); } // Collations didn't come in until MySQL 4.1. Anything earlier will throw a syntax error if you try and use @@ -615,7 +615,7 @@ abstract class DBSchemaManager { // Get the version of the field as we would create it. This is used for comparison purposes to see if the // existing field is different to what we now want if (is_array($spec_orig)) { - $spec_orig = $this->$spec_orig['type']($spec_orig['parts']); + $spec_orig = $this->{$spec_orig['type']}($spec_orig['parts']); } if ($newTable || $fieldValue == '') { diff --git a/model/fieldtypes/Bigint.php b/model/fieldtypes/Bigint.php index 482d069ce..c177adede 100644 --- a/model/fieldtypes/Bigint.php +++ b/model/fieldtypes/Bigint.php @@ -8,7 +8,7 @@ * @subpackage model * @see Int */ -class BigInt extends Int { +class BigInt extends DBInt { public function requireField() { $parts = array( diff --git a/model/fieldtypes/Float.php b/model/fieldtypes/DBFloat.php similarity index 97% rename from model/fieldtypes/Float.php rename to model/fieldtypes/DBFloat.php index 809b2b628..ab6a55f6d 100644 --- a/model/fieldtypes/Float.php +++ b/model/fieldtypes/DBFloat.php @@ -5,7 +5,7 @@ * @package framework * @subpackage model */ -class Float extends DBField { +class DBFloat extends DBField { public function __construct($name = null, $defaultVal = 0) { $this->defaultVal = is_float($defaultVal) ? $defaultVal : (float) 0; diff --git a/model/fieldtypes/Int.php b/model/fieldtypes/DBInt.php similarity index 97% rename from model/fieldtypes/Int.php rename to model/fieldtypes/DBInt.php index 549679f18..5357dc706 100644 --- a/model/fieldtypes/Int.php +++ b/model/fieldtypes/DBInt.php @@ -5,7 +5,7 @@ * @package framework * @subpackage model */ -class Int extends DBField { +class DBInt extends DBField { public function __construct($name = null, $defaultVal = 0) { $this->defaultVal = is_int($defaultVal) ? $defaultVal : 0; @@ -63,4 +63,3 @@ class Int extends DBField { } } - diff --git a/model/fieldtypes/Double.php b/model/fieldtypes/Double.php index 5d9445865..6bbaee4f1 100644 --- a/model/fieldtypes/Double.php +++ b/model/fieldtypes/Double.php @@ -4,7 +4,7 @@ * @package framework * @subpackage model */ -class Double extends Float { +class Double extends DBFloat { public function requireField() { // HACK: MSSQL does not support double so we're using float instead diff --git a/model/fieldtypes/ForeignKey.php b/model/fieldtypes/ForeignKey.php index 5850abc72..65829b635 100644 --- a/model/fieldtypes/ForeignKey.php +++ b/model/fieldtypes/ForeignKey.php @@ -12,7 +12,7 @@ * @package framework * @subpackage model */ -class ForeignKey extends Int { +class ForeignKey extends DBInt { /** * @var DataObject diff --git a/model/fieldtypes/PrimaryKey.php b/model/fieldtypes/PrimaryKey.php index a741cf14c..2051e3d97 100644 --- a/model/fieldtypes/PrimaryKey.php +++ b/model/fieldtypes/PrimaryKey.php @@ -7,7 +7,7 @@ * @package framework * @subpackage model */ -class PrimaryKey extends Int { +class PrimaryKey extends DBInt { /** * @var DataObject */ diff --git a/model/fieldtypes/compat/Float.php b/model/fieldtypes/compat/Float.php new file mode 100644 index 000000000..2364cd7b0 --- /dev/null +++ b/model/fieldtypes/compat/Float.php @@ -0,0 +1,6 @@ + "/framework/model/fieldtypes/compat/Int.php", + "float" => "/framework/model/fieldtypes/compat/Float.php", + ); + + $classname = strtolower($classname); + if(isset($classMap[$classname])) { + require_once BASE_PATH . $classMap[$classname]; + } +} diff --git a/tests/model/DBFieldTest.php b/tests/model/DBFieldTest.php index 68c071447..d19baea68 100644 --- a/tests/model/DBFieldTest.php +++ b/tests/model/DBFieldTest.php @@ -229,6 +229,25 @@ class DBFieldTest extends SapphireTest { $this->assertEquals('åäö', DBField::create_field('Text', 'ÅÄÖ')->LowerCase()); } + public function testIntFloatPhp5Behaviour() { + if (PHP_MAJOR_VERSION < 7) { + // PHP 5 - Int class exists and is an instance of DBInt + // Can't use the reserved words for these classes or we'll get a compile error on PHP7 + $classname = "int"; + $obj = new $classname(); + $this->assertInstanceOf('DBInt', $obj); + + $classname = "float"; + $obj = new $classname(); + $this->assertInstanceOf('DBFloat', $obj); + + } else { + // PHP 7 - classes don't exist + $this->assertFalse(class_exists("Int")); + $this->assertFalse(class_exists("Float")); + } + + } } diff --git a/tests/model/VersionedTest.php b/tests/model/VersionedTest.php index e6f24367b..ecad71788 100644 --- a/tests/model/VersionedTest.php +++ b/tests/model/VersionedTest.php @@ -180,11 +180,11 @@ class VersionedTest extends SapphireTest { public function testVersionedFieldsAdded() { $obj = new VersionedTest_DataObject(); // Check that the Version column is added as a full-fledged column - $this->assertInstanceOf('Int', $obj->dbObject('Version')); + $this->assertInstanceOf('DBInt', $obj->dbObject('Version')); $obj2 = new VersionedTest_Subclass(); // Check that the Version column is added as a full-fledged column - $this->assertInstanceOf('Int', $obj2->dbObject('Version')); + $this->assertInstanceOf('DBInt', $obj2->dbObject('Version')); } public function testVersionedFieldsNotInCMS() { diff --git a/view/SSViewer.php b/view/SSViewer.php index 78ad36074..f88fa6468 100644 --- a/view/SSViewer.php +++ b/view/SSViewer.php @@ -536,7 +536,7 @@ class SSViewer_DataPresenter extends SSViewer_Scope { // If not provided, use default if (!$casting) $casting = Config::inst()->get('ViewableData', 'default_cast', Config::FIRST_SET); - $obj = new $casting($property); + $obj = Injector::inst()->create($casting, false, array($property)); $obj->setValue($res['value']); $res['obj'] = $obj; diff --git a/view/ViewableData.php b/view/ViewableData.php index 59adb7eb7..c73341cd9 100644 --- a/view/ViewableData.php +++ b/view/ViewableData.php @@ -331,7 +331,7 @@ class ViewableData extends Object implements IteratorAggregate { public function escapeTypeForField($field) { $class = $this->castingClass($field) ?: $this->config()->default_cast; - return Config::inst()->get($class, 'escape_type', Config::FIRST_SET); + return Injector::inst()->get($class, true)->config()->escape_type; } /** From cca7e9697cd8b8523d52492cd686e06995d94f91 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 27 Aug 2015 13:10:48 +1200 Subject: [PATCH 02/12] FIX: Correct PHP4-style constructors in SimpleTest. Note that the best solution to this will be to remove the use of SimpleTest entirely. This is quick fix is intended to help us get PHP7 tests running without needing to cross that bridge. --- thirdparty/simpletest/cookies.php | 4 +- thirdparty/simpletest/encoding.php | 29 ++++-------- thirdparty/simpletest/form.php | 2 +- thirdparty/simpletest/http.php | 14 +++--- thirdparty/simpletest/page.php | 7 ++- thirdparty/simpletest/parser.php | 14 +++--- thirdparty/simpletest/selector.php | 8 ++-- thirdparty/simpletest/socket.php | 10 ++-- thirdparty/simpletest/tag.php | 75 +++++++++++++++--------------- thirdparty/simpletest/url.php | 2 +- 10 files changed, 76 insertions(+), 89 deletions(-) diff --git a/thirdparty/simpletest/cookies.php b/thirdparty/simpletest/cookies.php index f462e1b67..0b46a108e 100644 --- a/thirdparty/simpletest/cookies.php +++ b/thirdparty/simpletest/cookies.php @@ -36,7 +36,7 @@ class SimpleCookie { * @param string $expiry Expiry date as string. * @param boolean $is_secure Currently ignored. */ - function SimpleCookie($name, $value = false, $path = false, $expiry = false, $is_secure = false) { + function __construct($name, $value = false, $path = false, $expiry = false, $is_secure = false) { $this->_host = false; $this->_name = $name; $this->_value = $value; @@ -232,7 +232,7 @@ class SimpleCookieJar { * Constructor. Jar starts empty. * @access public */ - function SimpleCookieJar() { + function __construct() { $this->_cookies = array(); } diff --git a/thirdparty/simpletest/encoding.php b/thirdparty/simpletest/encoding.php index 162d09eed..0299aaca7 100644 --- a/thirdparty/simpletest/encoding.php +++ b/thirdparty/simpletest/encoding.php @@ -26,7 +26,7 @@ class SimpleEncodedPair { * @param string $key Form element name. * @param string $value Data to send. */ - function SimpleEncodedPair($key, $value) { + function __construct($key, $value) { $this->_key = $key; $this->_value = $value; } @@ -97,7 +97,7 @@ class SimpleAttachment { * @param string $content Raw data. * @param hash $filename Original filename. */ - function SimpleAttachment($key, $content, $filename) { + function __construct($key, $content, $filename) { $this->_key = $key; $this->_content = $content; $this->_filename = $filename; @@ -198,7 +198,7 @@ class SimpleEncoding { * as lists on a single key. * @access public */ - function SimpleEncoding($query = false) { + function __construct($query = false) { if (! $query) { $query = array(); } @@ -328,17 +328,6 @@ class SimpleEncoding { */ class SimpleGetEncoding extends SimpleEncoding { - /** - * Starts empty. - * @param array $query Hash of parameters. - * Multiple values are - * as lists on a single key. - * @access public - */ - function SimpleGetEncoding($query = false) { - $this->SimpleEncoding($query); - } - /** * HTTP request method. * @return string Always GET. @@ -390,8 +379,8 @@ class SimpleHeadEncoding extends SimpleGetEncoding { * as lists on a single key. * @access public */ - function SimpleHeadEncoding($query = false) { - $this->SimpleGetEncoding($query); + function __construct($query = false) { + parent::__construct($query); } /** @@ -419,11 +408,11 @@ class SimplePostEncoding extends SimpleEncoding { * as lists on a single key. * @access public */ - function SimplePostEncoding($query = false) { + function __construct($query = false) { if (is_array($query) and $this->hasMoreThanOneLevel($query)) { $query = $this->rewriteArrayWithMultipleLevels($query); } - $this->SimpleEncoding($query); + parent::__construct($query); } function hasMoreThanOneLevel($query) { @@ -509,8 +498,8 @@ class SimpleMultipartEncoding extends SimplePostEncoding { * as lists on a single key. * @access public */ - function SimpleMultipartEncoding($query = false, $boundary = false) { - $this->SimplePostEncoding($query); + function __construct($query = false, $boundary = false) { + parent::__construct($query); $this->_boundary = ($boundary === false ? uniqid('st') : $boundary); } diff --git a/thirdparty/simpletest/form.php b/thirdparty/simpletest/form.php index be85e2e01..de1705949 100644 --- a/thirdparty/simpletest/form.php +++ b/thirdparty/simpletest/form.php @@ -36,7 +36,7 @@ class SimpleForm { * @param SimpleTag $tag Form tag to read. * @param SimplePage $page Holding page. */ - function SimpleForm($tag, &$page) { + function __construct($tag, &$page) { $this->_method = $tag->getAttribute('method'); $this->_action = $this->_createAction($tag->getAttribute('action'), $page); $this->_encoding = $this->_setEncodingClass($tag); diff --git a/thirdparty/simpletest/http.php b/thirdparty/simpletest/http.php index 367504413..5f109e650 100644 --- a/thirdparty/simpletest/http.php +++ b/thirdparty/simpletest/http.php @@ -28,7 +28,7 @@ class SimpleRoute { * @param SimpleUrl $url URL as object. * @access public */ - function SimpleRoute($url) { + function __construct($url) { $this->_url = $url; } @@ -125,8 +125,8 @@ class SimpleProxyRoute extends SimpleRoute { * @param string $password Password for autentication. * @access public */ - function SimpleProxyRoute($url, $proxy, $username = false, $password = false) { - $this->SimpleRoute($url); + function __construct($url, $proxy, $username = false, $password = false) { + parent::__construct($url); $this->_proxy = $proxy; $this->_username = $username; $this->_password = $password; @@ -208,7 +208,7 @@ class SimpleHttpRequest { * request. * @access public */ - function SimpleHttpRequest(&$route, $encoding) { + function __construct(&$route, $encoding) { $this->_route = &$route; $this->_encoding = $encoding; $this->_headers = array(); @@ -307,7 +307,7 @@ class SimpleHttpHeaders { * @param string $headers Header block. * @access public */ - function SimpleHttpHeaders($headers) { + function __construct($headers) { $this->_raw_headers = $headers; $this->_response_code = false; $this->_http_version = false; @@ -494,8 +494,8 @@ class SimpleHttpResponse extends SimpleStickyError { * @param mixed $encoding Record of content sent. * @access public */ - function SimpleHttpResponse(&$socket, $url, $encoding) { - $this->SimpleStickyError(); + function __construct(&$socket, $url, $encoding) { + parent::__construct(); $this->_url = $url; $this->_encoding = $encoding; $this->_sent = $socket->getSent(); diff --git a/thirdparty/simpletest/page.php b/thirdparty/simpletest/page.php index add422371..c1e08957d 100644 --- a/thirdparty/simpletest/page.php +++ b/thirdparty/simpletest/page.php @@ -127,10 +127,9 @@ class SimplePageBuilder extends SimpleSaxListener { * Sets the builder up empty. * @access public */ - function SimplePageBuilder() { - $this->SimpleSaxListener(); + function __construct() { + parent::__construct(); } - /** * Frees up any references so as to allow the PHP garbage * collection from unset() to work. @@ -358,7 +357,7 @@ class SimplePage { * @param SimpleHttpResponse $response Result of HTTP fetch. * @access public */ - function SimplePage($response = false) { + function __construct($response = false) { $this->_links = array(); $this->_title = false; $this->_left_over_labels = array(); diff --git a/thirdparty/simpletest/parser.php b/thirdparty/simpletest/parser.php index 35616d717..c4cb492ff 100644 --- a/thirdparty/simpletest/parser.php +++ b/thirdparty/simpletest/parser.php @@ -37,7 +37,7 @@ class ParallelRegex { * for insensitive. * @access public */ - function ParallelRegex($case) { + function __construct($case) { $this->_case = $case; $this->_patterns = array(); $this->_labels = array(); @@ -129,7 +129,7 @@ class SimpleStateStack { * @param string $start Starting state name. * @access public */ - function SimpleStateStack($start) { + function __construct($start) { $this->_stack = array($start); } @@ -193,7 +193,7 @@ class SimpleLexer { * @param boolean $case True for case sensitive. * @access public */ - function SimpleLexer(&$parser, $start = "accept", $case = false) { + function __construct(&$parser, $start = "accept", $case = false) { $this->_case = $case; $this->_regexes = array(); $this->_parser = &$parser; @@ -456,8 +456,8 @@ class SimpleHtmlLexer extends SimpleLexer { * reference. * @access public */ - function SimpleHtmlLexer(&$parser) { - $this->SimpleLexer($parser, 'text'); + function __construct(&$parser) { + parent::__construct($parser, 'text'); $this->mapHandler('text', 'acceptTextToken'); $this->_addSkipping(); foreach ($this->_getParsedTags() as $tag) { @@ -552,7 +552,7 @@ class SimpleHtmlSaxParser { * @param SimpleSaxListener $listener SAX event handler. * @access public */ - function SimpleHtmlSaxParser(&$listener) { + function __construct(&$listener) { $this->_listener = &$listener; $this->_lexer = &$this->createLexer($this); $this->_tag = ''; @@ -728,7 +728,7 @@ class SimpleSaxListener { * Sets the document to write to. * @access public */ - function SimpleSaxListener() { + function __construct() { } /** diff --git a/thirdparty/simpletest/selector.php b/thirdparty/simpletest/selector.php index c33af1bfc..8fdfbd13e 100644 --- a/thirdparty/simpletest/selector.php +++ b/thirdparty/simpletest/selector.php @@ -26,7 +26,7 @@ class SimpleByName { * Stashes the name for later comparison. * @param string $name Name attribute to match. */ - function SimpleByName($name) { + function __construct($name) { $this->_name = $name; } @@ -57,7 +57,7 @@ class SimpleByLabel { * Stashes the name for later comparison. * @param string $label Visible text to match. */ - function SimpleByLabel($label) { + function __construct($label) { $this->_label = $label; } @@ -88,7 +88,7 @@ class SimpleById { * Stashes the name for later comparison. * @param string $id ID atribute to match. */ - function SimpleById($id) { + function __construct($id) { $this->_id = $id; } @@ -115,7 +115,7 @@ class SimpleByLabelOrName { * Stashes the name/label for later comparison. * @param string $label Visible text to match. */ - function SimpleByLabelOrName($label) { + function __construct($label) { $this->_label = $label; } diff --git a/thirdparty/simpletest/socket.php b/thirdparty/simpletest/socket.php index 1d4c97ba6..d77d43fcb 100644 --- a/thirdparty/simpletest/socket.php +++ b/thirdparty/simpletest/socket.php @@ -25,7 +25,7 @@ class SimpleStickyError { * Sets the error to empty. * @access public */ - function SimpleStickyError() { + function __construct() { $this->_clearError(); } @@ -85,8 +85,8 @@ class SimpleSocket extends SimpleStickyError { * @param integer $block_size Size of chunk to read. * @access public */ - function SimpleSocket($host, $port, $timeout, $block_size = 255) { - $this->SimpleStickyError(); + function __construct($host, $port, $timeout, $block_size = 255) { + parent::__construct(); if (! ($this->_handle = $this->_openSocket($host, $port, $error_number, $error, $timeout))) { $this->_setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds"); return; @@ -196,8 +196,8 @@ class SimpleSecureSocket extends SimpleSocket { * @param integer $timeout Connection timeout in seconds. * @access public */ - function SimpleSecureSocket($host, $port, $timeout) { - $this->SimpleSocket($host, $port, $timeout); + function __construct($host, $port, $timeout) { + parent::__construct($host, $port, $timeout); } /** diff --git a/thirdparty/simpletest/tag.php b/thirdparty/simpletest/tag.php index e91396513..0cb1bf9a4 100644 --- a/thirdparty/simpletest/tag.php +++ b/thirdparty/simpletest/tag.php @@ -31,7 +31,7 @@ class SimpleTag { * the keys must have been * converted to lower case. */ - function SimpleTag($name, $attributes) { + function __construct($name, $attributes) { $this->_name = strtolower(trim($name)); $this->_attributes = $attributes; $this->_content = ''; @@ -162,8 +162,8 @@ class SimpleBaseTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleBaseTag($attributes) { - $this->SimpleTag('base', $attributes); + function __construct($attributes) { + parent::__construct('base', $attributes); } /** @@ -188,8 +188,8 @@ class SimpleTitleTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleTitleTag($attributes) { - $this->SimpleTag('title', $attributes); + function __construct($attributes) { + parent::__construct('title', $attributes); } } @@ -205,8 +205,8 @@ class SimpleAnchorTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleAnchorTag($attributes) { - $this->SimpleTag('a', $attributes); + function __construct($attributes) { + parent::__construct('a', $attributes); } /** @@ -239,8 +239,8 @@ class SimpleWidget extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleWidget($name, $attributes) { - $this->SimpleTag($name, $attributes); + function __construct($name, $attributes) { + parent::__construct($name, $attributes); $this->_value = false; $this->_label = false; $this->_is_set = false; @@ -344,8 +344,8 @@ class SimpleTextTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleTextTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', ''); } @@ -387,8 +387,8 @@ class SimpleSubmitTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleSubmitTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'Submit'); } @@ -445,10 +445,9 @@ class SimpleImageSubmitTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleImageSubmitTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); } - /** * Tag contains no end element. * @return boolean False. @@ -521,8 +520,8 @@ class SimpleButtonTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleButtonTag($attributes) { - $this->SimpleWidget('button', $attributes); + function __construct($attributes) { + parent::__construct('button', $attributes); } /** @@ -577,8 +576,8 @@ class SimpleTextAreaTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleTextAreaTag($attributes) { - $this->SimpleWidget('textarea', $attributes); + function __construct($attributes) { + parent::__construct('textarea', $attributes); } /** @@ -662,8 +661,8 @@ class SimpleUploadTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleUploadTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); } /** @@ -705,8 +704,8 @@ class SimpleSelectionTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleSelectionTag($attributes) { - $this->SimpleWidget('select', $attributes); + function __construct($attributes) { + parent::__construct('select', $attributes); $this->_options = array(); $this->_choice = false; } @@ -792,8 +791,8 @@ class MultipleSelectionTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function MultipleSelectionTag($attributes) { - $this->SimpleWidget('select', $attributes); + function __construct($attributes) { + parent::__construct('select', $attributes); $this->_options = array(); $this->_values = false; } @@ -883,8 +882,8 @@ class SimpleOptionTag extends SimpleWidget { /** * Stashes the attributes. */ - function SimpleOptionTag($attributes) { - $this->SimpleWidget('option', $attributes); + function __construct($attributes) { + parent::__construct('option', $attributes); } /** @@ -945,8 +944,8 @@ class SimpleRadioButtonTag extends SimpleWidget { * Stashes the attributes. * @param array $attributes Hash of attributes. */ - function SimpleRadioButtonTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'on'); } @@ -1003,8 +1002,8 @@ class SimpleCheckboxTag extends SimpleWidget { * @param hash $attributes Attribute names and * string values. */ - function SimpleCheckboxTag($attributes) { - $this->SimpleWidget('input', $attributes); + function __construct($attributes) { + parent::__construct('input', $attributes); if ($this->getAttribute('value') === false) { $this->_setAttribute('value', 'on'); } @@ -1359,8 +1358,8 @@ class SimpleLabelTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleLabelTag($attributes) { - $this->SimpleTag('label', $attributes); + function __construct($attributes) { + parent::__construct('label', $attributes); } /** @@ -1385,8 +1384,8 @@ class SimpleFormTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleFormTag($attributes) { - $this->SimpleTag('form', $attributes); + function __construct($attributes) { + parent::__construct('form', $attributes); } } @@ -1402,8 +1401,8 @@ class SimpleFrameTag extends SimpleTag { * @param hash $attributes Attribute names and * string values. */ - function SimpleFrameTag($attributes) { - $this->SimpleTag('frame', $attributes); + function __construct($attributes) { + parent::__construct('frame', $attributes); } /** diff --git a/thirdparty/simpletest/url.php b/thirdparty/simpletest/url.php index cdd725079..8bef380ab 100644 --- a/thirdparty/simpletest/url.php +++ b/thirdparty/simpletest/url.php @@ -41,7 +41,7 @@ class SimpleUrl { * @param string $url Incoming URL. * @access public */ - function SimpleUrl($url = '') { + function __construct($url = '') { list($x, $y) = $this->_chompCoordinates($url); $this->setCoordinates($x, $y); $this->_scheme = $this->_chompScheme($url); From 82f62c818430314f3607c2ad87776740ccfccefb Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Mon, 3 Apr 2017 21:33:33 +0100 Subject: [PATCH 03/12] Fix illegal string offset in spyc component --- thirdparty/spyc/spyc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thirdparty/spyc/spyc.php b/thirdparty/spyc/spyc.php index fb11c6646..f954dcc2a 100644 --- a/thirdparty/spyc/spyc.php +++ b/thirdparty/spyc/spyc.php @@ -769,7 +769,8 @@ class Spyc { $_arr = array_merge ($_arr, $value); } else if ($key || $key === '') { - $_arr[$key] = $value; + if (!is_array ($_arr)) { $_arr = array ($key=>$value); } + else { $_arr[$key] = $value; } } else { if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; } else { $_arr[] = $value; end ($_arr); $key = key ($_arr); } From 05a737c5fc2d9d5bda86a3d78562c566f30b4b0c Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Mon, 3 Apr 2017 22:13:07 +0100 Subject: [PATCH 04/12] Allow RandomGenerator to use random_bytes() in PHP 7 --- security/RandomGenerator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/security/RandomGenerator.php b/security/RandomGenerator.php index 52ac1a858..42cd4fb72 100644 --- a/security/RandomGenerator.php +++ b/security/RandomGenerator.php @@ -17,6 +17,10 @@ class RandomGenerator { * @return string Returns a random series of bytes */ public function generateEntropy() { + if (function_exists('random_bytes')) { + return bin2hex(random_bytes(32)); + } + $isWin = preg_match('/WIN/', PHP_OS); // TODO Fails with "Could not gather sufficient random data" on IIS, temporarily disabled on windows From 454646c4dfda323a66e42ed46797fdad4a12d176 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Mon, 3 Apr 2017 22:33:38 +0100 Subject: [PATCH 05/12] Fix invalid closure param in ShortcodeParserTest --- tests/parsers/ShortcodeParserTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/parsers/ShortcodeParserTest.php b/tests/parsers/ShortcodeParserTest.php index 796d06478..a04c31bd3 100644 --- a/tests/parsers/ShortcodeParserTest.php +++ b/tests/parsers/ShortcodeParserTest.php @@ -252,7 +252,7 @@ class ShortcodeParserTest extends SapphireTest { $this->parser->parse('') ); - $this->parser->register('2', function($attributes, $content, $this, $tag, $extra) { + $this->parser->register('2', function($attributes, $content, $parser, $tag, $extra) { return 'this is 2'; }); From f224849cc6c93024ed305a6ca82df8fd08c8df80 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Fri, 28 Aug 2015 16:42:43 +1200 Subject: [PATCH 06/12] =?UTF-8?q?FIX:=20Don=E2=80=99t=20use=20SplFixedArra?= =?UTF-8?q?y=20in=20PHP=207.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHP 7 seems to suffer a segfault when using SplFixedArray. Since LRU is deprecated anyway, I’m not too fussed about getting to the bottom of this issue, however, if it turns out that SplFixedArray is corrected in PHP 7.0.0 stable or a future patch release, we could update this check. --- core/Config.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Config.php b/core/Config.php index 414350995..50c6e1942 100644 --- a/core/Config.php +++ b/core/Config.php @@ -704,8 +704,8 @@ class Config_LRU { public function __construct() { Deprecation::notice('4.0', 'Please use Config_MemCache instead', Deprecation::SCOPE_CLASS); - if (version_compare(PHP_VERSION, '5.3.7', '<')) { - // SplFixedArray causes seg faults before PHP 5.3.7 + if (version_compare(PHP_VERSION, '5.3.7', '<') || version_compare(PHP_VERSION, '6.99.99', '>')) { + // SplFixedArray causes seg faults before PHP 5.3.7, and also in 7.0.0-RC1 $this->cache = array(); } else { From 22ad39e5aea301fa932894d444191dd6ef6389af Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Wed, 26 Oct 2016 14:31:45 +1300 Subject: [PATCH 07/12] FIX: Fix SSViewerTest in PHP7 PHP7 is a bit more picky about passing values by reference. --- tests/view/SSViewerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/view/SSViewerTest.php b/tests/view/SSViewerTest.php index 440e3fdc0..62cd678bc 100644 --- a/tests/view/SSViewerTest.php +++ b/tests/view/SSViewerTest.php @@ -1491,7 +1491,7 @@ EOC; $parser = new SSTemplateParser(); $parser->addClosedBlock( 'test', - function (&$res) use (&$count) { + function ($res) use (&$count) { $count++; } ); @@ -1507,7 +1507,7 @@ EOC; $parser = new SSTemplateParser(); $parser->addOpenBlock( 'test', - function (&$res) use (&$count) { + function ($res) use (&$count) { $count++; } ); From f083a06f3f97c34079a7d37692f2968df24fe8ff Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Tue, 4 Apr 2017 17:06:57 +1000 Subject: [PATCH 08/12] FIX: Fix ViewableData::__isset() for getXXX() getters. PHP7 is stricter about this. Manual cherry-pick of of c80417a949c7f2821ab4ce1f76ccbc5b6649fcaf --- view/ViewableData.php | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/view/ViewableData.php b/view/ViewableData.php index c73341cd9..ce1d35e92 100644 --- a/view/ViewableData.php +++ b/view/ViewableData.php @@ -93,7 +93,18 @@ class ViewableData extends Object implements IteratorAggregate { * @return bool */ public function __isset($property) { - return $this->hasField($property) || ($this->failover && $this->failover->hasField($property)); + // getField() isn't a field-specific getter and shouldn't be treated as such + if (strtolower($property) !== 'field' && $this->hasMethod($method = "get$property")) { + return true; + + } elseif ($this->hasField($property)) { + return true; + + } elseif ($this->failover) { + return isset($this->failover->$property); + } + + return false; } /** @@ -104,13 +115,17 @@ class ViewableData extends Object implements IteratorAggregate { * @return mixed */ public function __get($property) { - if($this->hasMethod($method = "get$property")) { + // getField() isn't a field-specific getter and shouldn't be treated as such + if (strtolower($property) !== 'field' && $this->hasMethod($method = "get$property")) { return $this->$method(); - } elseif($this->hasField($property)) { + + } elseif ($this->hasField($property)) { return $this->getField($property); - } elseif($this->failover) { + + } elseif ($this->failover) { return $this->failover->$property; } + return null; } /** From e22cd4db00f2afb69b7c7f6572c109e627776dbe Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Tue, 4 Apr 2017 09:52:54 +0100 Subject: [PATCH 09/12] Fix: TabSet attempting to access undeclared property --- forms/TabSet.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forms/TabSet.php b/forms/TabSet.php index bf404993e..dc5ec3b2a 100644 --- a/forms/TabSet.php +++ b/forms/TabSet.php @@ -27,6 +27,8 @@ */ class TabSet extends CompositeField { + protected $tabSet; + /** * @param string $name Identifier * @param string $title (Optional) Natural language title of the tabset From f101697f8ef5dac427c7c3b65c457f5c6c1ab090 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Tue, 4 Apr 2017 10:02:21 +0100 Subject: [PATCH 10/12] Fix File::ini2bytes() in PHP 7 --- filesystem/File.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/filesystem/File.php b/filesystem/File.php index 6b66319ac..f6aca1d1f 100644 --- a/filesystem/File.php +++ b/filesystem/File.php @@ -883,19 +883,28 @@ class File extends DataObject { /** * Convert a php.ini value (eg: 512M) to bytes * - * @param string $phpIniValue + * @param string $iniValue * @return int */ - public static function ini2bytes($PHPiniValue) { - switch(strtolower(substr(trim($PHPiniValue), -1))) { + public static function ini2bytes($iniValue) { + $iniValues = str_split(trim($iniValue)); + $unit = strtolower(array_pop($iniValues)); + $quantity = (int) implode($iniValues); + switch ($unit) { case 'g': - $PHPiniValue *= 1024; + $quantity *= 1024; + // deliberate no break case 'm': - $PHPiniValue *= 1024; + $quantity *= 1024; + // deliberate no break case 'k': - $PHPiniValue *= 1024; + $quantity *= 1024; + // deliberate no break + default: + // no-op: pre-existing behaviour + break; } - return $PHPiniValue; + return $quantity; } /** From ae0fe75fba35918735656ea82cab2e7584b27f07 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Tue, 4 Apr 2017 10:38:55 +0100 Subject: [PATCH 11/12] Fix non-numeric warnings in GDBackend/ImagickBackend intval() will convert non-numeric values to 0, and Image_Backend::resize() will subsequently raise the appropriate exception --- filesystem/GD.php | 11 +++++++++++ filesystem/ImagickBackend.php | 19 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/filesystem/GD.php b/filesystem/GD.php index 7cd4c3aad..89d2dfc86 100644 --- a/filesystem/GD.php +++ b/filesystem/GD.php @@ -220,6 +220,8 @@ class GDBackend extends Object implements Image_Backend { * @todo This method isn't very efficent */ public function fittedResize($width, $height) { + $width = intval($width); + $height = intval($height); $gd = $this->resizeByHeight($height); if($gd->width > $width) $gd = $gd->resizeByWidth($width); return $gd; @@ -354,6 +356,11 @@ class GDBackend extends Object implements Image_Backend { */ public function crop($top, $left, $width, $height) { + $top = intval($top); + $left = intval($left); + $width = intval($width); + $height = intval($height); + $newGD = imagecreatetruecolor($width, $height); // Preserve alpha channel between images @@ -390,6 +397,7 @@ class GDBackend extends Object implements Image_Backend { * Resize an image by width. Preserves aspect ratio. */ public function resizeByWidth( $width ) { + $width = intval($width); $heightScale = $width / $this->width; return $this->resize( $width, $heightScale * $this->height ); } @@ -398,6 +406,7 @@ class GDBackend extends Object implements Image_Backend { * Resize an image by height. Preserves aspect ratio */ public function resizeByHeight( $height ) { + $height = intval($height); $scale = $height / $this->height; return $this->resize( $scale * $this->width, $height ); } @@ -407,6 +416,8 @@ class GDBackend extends Object implements Image_Backend { * and maxHeight. Passing useAsMinimum will make the smaller dimension equal to the maximum corresponding dimension */ public function resizeRatio( $maxWidth, $maxHeight, $useAsMinimum = false ) { + $maxWidth = intval($maxWidth); + $maxHeight = intval($maxHeight); $widthRatio = $maxWidth / $this->width; $heightRatio = $maxHeight / $this->height; diff --git a/filesystem/ImagickBackend.php b/filesystem/ImagickBackend.php index 0399af1e6..901315994 100644 --- a/filesystem/ImagickBackend.php +++ b/filesystem/ImagickBackend.php @@ -148,6 +148,9 @@ class ImagickBackend extends Imagick implements Image_Backend { public function resizeRatio($maxWidth, $maxHeight, $useAsMinimum = false) { if(!$this->valid()) return; + $maxWidth = intval($maxWidth); + $maxHeight = intval($maxHeight); + $geometry = $this->getImageGeometry(); $widthRatio = $maxWidth / $geometry["width"]; @@ -168,6 +171,8 @@ class ImagickBackend extends Imagick implements Image_Backend { public function resizeByWidth($width) { if(!$this->valid()) return; + $width = intval($width); + $geometry = $this->getImageGeometry(); $heightScale = $width / $geometry["width"]; @@ -183,6 +188,8 @@ class ImagickBackend extends Imagick implements Image_Backend { public function resizeByHeight($height) { if(!$this->valid()) return; + $height = intval($height); + $geometry = $this->getImageGeometry(); $scale = $height / $geometry["height"]; @@ -198,6 +205,9 @@ class ImagickBackend extends Imagick implements Image_Backend { * @return Image_Backend */ public function paddedResize($width, $height, $backgroundColor = "FFFFFF", $transparencyPercent = 0) { + $width = intval($width); + $height = intval($height); + //keep the % within bounds of 0-100 $transparencyPercent = min(100, max(0, $transparencyPercent)); $new = $this->resizeRatio($width, $height); @@ -265,7 +275,7 @@ class ImagickBackend extends Imagick implements Image_Backend { $new->ThumbnailImage($width,$height,true); return $new; } - + /** * Crop's part of image. * @param int $top y position of left upper corner of crop rectangle @@ -275,9 +285,14 @@ class ImagickBackend extends Imagick implements Image_Backend { * @return Image_Backend */ public function crop($top, $left, $width, $height) { + $top = intval($top); + $left = intval($left); + $width = intval($width); + $height = intval($height); + $new = clone $this; $new->cropImage($width, $height, $left, $top); - + return $new; } From 061b71328be7732568e634e40c38389b63d8833e Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Wed, 5 Apr 2017 11:04:21 +1000 Subject: [PATCH 12/12] Update docs. --- docs/en/00_Getting_Started/00_Server_Requirements.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/en/00_Getting_Started/00_Server_Requirements.md b/docs/en/00_Getting_Started/00_Server_Requirements.md index 24d162b22..90bae7b5f 100644 --- a/docs/en/00_Getting_Started/00_Server_Requirements.md +++ b/docs/en/00_Getting_Started/00_Server_Requirements.md @@ -8,7 +8,7 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme ## Web server software requirements - * PHP 5.3.3+, <7 + * PHP 5.3.3+, <7.2 * We recommend using a PHP accelerator or opcode cache, such as [xcache](http://xcache.lighttpd.net/) or [WinCache](http://www.iis.net/download/wincacheforphp). * Allocate at least 48MB of memory to each PHP process. (SilverStripe can be resource hungry for some intensive operations.) * Required modules: dom, gd2, fileinfo, hash, iconv, mbstring, mysqli (or other database driver), session, simplexml, tokenizer, xml. @@ -34,10 +34,9 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme * Microsoft Windows XP SP3, Vista, Windows 7, Server 2008, Server 2008 R2 * Mac OS X 10.4+ -### Why doesn't SilverStripe 3 work with PHP 7? -Unfortunately, SilverStripe has classes named the same as PHP reserved words, such as "Int" and "Float". This means that -we are unable to make SilverStripe 3 support PHP 7 without breaking backward compatibility. SilverStripe 4 will work -with PHP 7 and will be released in 2016. Until then, we recommend that you use PHP 5.6. +### Does SilverStripe 3 work with PHP 7? +SilverStripe 3.6 or greater will work with PHP 7.0 and 7.1. SilverStripe 3.5 or lower will only work with PHP +5.3 - 5.6. ## Web server hardware requirements