From 6d285b078414e46ee991f9213341605e9c4c3045 Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Fri, 7 May 2021 08:33:25 -0400 Subject: [PATCH] Fix issue processwire/processwire-issues#1288 --- wire/core/Page.php | 2 +- wire/core/PageFinder.php | 25 +++++++++++---- wire/core/WireDateTime.php | 31 +++++++++++++++++++ wire/core/WireFileTools.php | 4 +-- .../InputfieldDatetime.module | 3 +- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/wire/core/Page.php b/wire/core/Page.php index 063bf540..550135e5 100644 --- a/wire/core/Page.php +++ b/wire/core/Page.php @@ -725,7 +725,7 @@ class Page extends WireData implements \Countable, WireMatchable { case 'modified': case 'published': if($value === null) $value = 0; - if($value && !ctype_digit("$value")) $value = strtotime($value); + if($value && !ctype_digit("$value")) $value = $this->wire()->datetime->strtotime($value); $value = (int) $value; if($this->isLoaded && $this->settings[$key] !== $value) $this->trackChange($key, $this->settings[$key], $value); $this->settings[$key] = $value; diff --git a/wire/core/PageFinder.php b/wire/core/PageFinder.php index 633779d7..72741cb3 100644 --- a/wire/core/PageFinder.php +++ b/wire/core/PageFinder.php @@ -2603,8 +2603,17 @@ class PageFinder extends Wire { } else if(in_array($field, array('created', 'modified', 'published'))) { // prepare value for created, modified or published date fields - if(!ctype_digit($value)) $value = strtotime($value); - $value = date('Y-m-d H:i:s', $value); + if(!ctype_digit($value)) { + $value = $this->wire()->datetime->strtotime($value); + } + if(empty($value)) { + $value = null; + if($operator === '>' || $operator === '=>') { + $value = $field === 'published' ? '1000-01-01 00:00:00' : '1970-01-01 00:00:01'; + } + } else { + $value = date('Y-m-d H:i:s', $value); + } } else if(in_array($field, array('id', 'parent_id', 'templates_id', 'sort'))) { $value = (int) $value; @@ -2676,10 +2685,14 @@ class PageFinder extends Wire { if($operator === '=' || $operator === '!=') $operator = '&'; // bitwise if($operator === '!=') $not = true; } - if(ctype_digit("$value") && $field != 'name') $value = (int) $value; - $bindKey = $query->bindValueGetKey($value); - $s = "$table.$field" . $operator . $bindKey; - if($not) $s = "NOT ($s)"; + if($value === null) { + $s = "$table.$field " . ($not ? 'IS NOT NULL' : 'IS NULL'); + } else { + if(ctype_digit("$value") && $field != 'name') $value = (int) $value; + $bindKey = $query->bindValueGetKey($value); + $s = "$table.$field" . $operator . $bindKey; + if($not) $s = "NOT ($s)"; + } if($field === 'status' && strpos($operator, '<') === 0 && $value >= Page::statusHidden && count($options['alwaysAllowIDs'])) { // support the 'alwaysAllowIDs' option for specific page IDs when requested but would diff --git a/wire/core/WireDateTime.php b/wire/core/WireDateTime.php index 37e36487..d748e7fc 100644 --- a/wire/core/WireDateTime.php +++ b/wire/core/WireDateTime.php @@ -417,6 +417,37 @@ class WireDateTime extends Wire { return $value; } + /** + * Parse about any English textual datetime description into a Unix timestamp using PHP’s strtotime() + * + * This function behaves the same as PHP’s version except that it optionally accepts an `$options` array + * and lets you specify the return value for empty or zeroed dates like 0000-00-00. If given a zerod date + * then it returns null by default (rather than throwing an error as PHP8 does). + * + * @param string $str Date/time string + * @param array|int $options Options to modify behavior, or specify int for the `baseTimestamp` option. + * - `emptyReturnValue` (int|null|false): Value to return for empty or zero-only date strings (default=null) + * - `baseTimestamp` (int|null): The timestamp which is used as a base for the calculation of relative dates. + * @return false|int|null + * @see https://www.php.net/manual/en/function.strtotime.php + * @since 3.0.178 + * + */ + function strtotime($str, $options = array()) { + $defaults = array( + 'emptyReturnValue' => null, + 'baseTimestamp' => null, + ); + if(is_int($options)) $defaults['baseTimestamp'] = $options; + $options = is_array($options) ? array_merge($defaults, $options) : $defaults; + $str = trim($str); + if(empty($str)) return $options['emptyReturnValue']; + if(strpos($str, '00') === 0) { + $test = trim(preg_replace('/[^\d]/', '', $str), '0'); + if(!strlen($test)) return $options['emptyReturnValue']; + } + return strtotime($str, $options['baseTimestamp']); + } /** diff --git a/wire/core/WireFileTools.php b/wire/core/WireFileTools.php index c8d66f93..8fa0e094 100644 --- a/wire/core/WireFileTools.php +++ b/wire/core/WireFileTools.php @@ -555,12 +555,12 @@ class WireFileTools extends Wire { * * ~~~~~ * $tempDir = $files->tempDir(); - * $path = $tempDir->get(); // or use $td->get(); + * $path = $tempDir->get(); * file_put_contents($path . 'some-file.txt', 'Hello world'); * ~~~~~ * * @param Object|string $name Any one of the following: (default='') - * - Omit this argument for auto-generated name, 3.0.175+ + * - Omit this argument for auto-generated name, 3.0.178+ * - Name/word that you specify using fieldName format, i.e. [_a-zA-Z0-9]. * - Object instance that needs the temp dir. * @param array|int $options Deprecated argument. Call `WireTempDir` methods if you need more options. diff --git a/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.module b/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.module index 55ce2a7d..e8657a12 100644 --- a/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.module +++ b/wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.module @@ -347,7 +347,8 @@ class InputfieldDatetime extends Inputfield { $value = (int) $value; } else if(strlen($value) > 8 && $value[4] === '-' && $value[7] === '-' && ctype_digit(substr($value, 0, 4))) { // ISO-8601, i.e. 2010-04-08 02:48:00 - $value = strtotime($value); + $value = $this->wire()->datetime->strtotime($value); + if(!$value) $value = ''; } else { $value = $this->getInputType()->sanitizeValue($value); }