Вопрос и ожидания
Хотя буквальная форма этого вопроса практична в контексте (1899 год), в теоретическом смысле она немного расплывчата. Сколько лет старому? Как далеко в прошлое , мы могли бы хотеть пойти? Как насчет будущего?
Так как WordPress начинал как движок блогов, в этом контексте он развивался, чтобы обрабатывать следующие промежутки времени:
- даты WP существовали (очевидно, чтобы иметь возможность использовать его)
- диапазон возможных исторических сообщений (неявно еще в существовании Интернета)
- как можно дальше в будущее без особых усилий (работайте до тех пор, пока оно не сломается)
Поскольку использование WordPress превратилось в приложения для ведения блогов, такие проекты (как правило, история и искусство, как я видел из отчетов) начали сталкиваться с различными проблемами с датами за пределами этого диапазона.
Для целей моего исследования я сформулировал следующие вопросы:
- Какие два самых ранних и последних полных календарных года можно использовать с датами публикации WordPress изначально и надежно?
- Что такое низко висящие фрукты (если таковые имеются), чтобы расширить доступный диапазон за пределы родного диапазона?
Ограничения платформы
Поскольку WordPress является PHP-приложением и использует MySQL для хранения данных, на него распространяются их ограничения.
MySQL
WordPress хранит даты публикации в post_date
столбце DATETIME
типа в MySQL.
Согласно документации этот тип поддерживает годы от 1000 до 9999 :
DATETIME
Типа используются для значений , которые содержат как дату и время часть. MySQL извлекает и отображает DATETIME
значения в 'YYYY-MM-DD HH:MM:SS'
формате. Поддерживаемый диапазон '1000-01-01 00:00:00'
до '9999-12-31 23:59:59'
.
Однако это также говорит о том, что более ранние значения могут работать, не говоря уже о более поздних значениях:
Для DATE and DATETIME
описаний диапазонов «поддерживаемый» означает, что, хотя более ранние значения могут работать, гарантии нет.
Хотя эмпирически я наблюдал значения вне рабочего диапазона, это анекдотично и не соответствует нашему уровню надежности.
PHP
В программировании PHP Unix timestamp представление даты широко используется. В соответствии с документацией для наших целей (PHP 5.2+ и общая 32-битная среда) он поддерживает годы (полностью) с 1902 по 2037 год :
Допустимый диапазон отметки времени обычно от Fri, 13 Dec 1901 20:45:54 UTC
до Tue, 19 Jan 2038 03:14:07 UTC
. (Это даты, которые соответствуют минимальным и максимальным значениям для 32-разрядного целого числа со знаком.) Кроме того, не все платформы поддерживают отрицательные временные метки, поэтому ваш диапазон дат может быть ограничен не ранее эпохи Unix. Это означает, что, например, даты до Jan 1, 1970
не будут работать в Windows, некоторых дистрибутивах Linux и некоторых других операционных системах. PHP 5.1.0 и более новые версии преодолевают это ограничение.
Кроме того, более новая Date/Time
обработка на основе 64-битной системы имеет диапазон от -292 до 292 млрд. Лет , что, вероятно, превышает потребности человечества в настоящее время.
Ограничения WordPress
WordPress вводит и наследует некоторые дополнительные ограничения в своей базе кода.
Поток данных
С точки зрения основного рабочего процесса пользователя, есть две обработки, связанные с датой:
- ввод даты в форме редактирования сообщения должен быть правильно обработан и сохранен в базе данных
- дата, сохраненная в базе данных, должна быть правильно прочитана и отображена в интерфейсе
Обратите внимание, что это технически совершенно разные и независимые процессы. Как поясняется далее, их диапазоны не перекрываются, и сохранение правильной даты не означает способность правильно читать ее в среде WordPress.
Явные ограничения
- Редактор сообщений WordPress в админке позволяет диапазон лет, который может быть представлен как дата публикации, от 100 до 9999
_wp_translate_postdata()
год обработки (представлен в виде отличного номера от формы) и:
- дезинфицирует его до неотрицательного > 0
- проверяет его, используя
wp_checkdate()
, который вызывает PHP родной checkdate()
, что накладывает ограничение от 1 до 32767
Неявные ограничения
strtotime()
Функция PHP используется несколько раз и подчиняется вышеупомянутой метке времени Unix, на самом низком уровне, mysql2date()
которая влияет на все чтения дат из базы данных, наследуемый диапазон с 1902 по 2037 год
- WordPress прибегает к регулярному выражению для разбора даты
get_gmt_from_date()
, которое ожидает год ([0-9]{1,4})
, ограничив его значением от 1 до 9999 , что дает высокую вероятность аналогичной обработки в других функциях, которые потребуют более тщательного аудита кода для перечисления
Возможность обхода
wp_checkdate()
имеет wp_checkdate
фильтр, который позволяет переопределить эту проверку проверки
- выход направлен на конечном пользователе проходит через
date_i18n()
которое имеет date_i18n
фильтр, теоретически позволяет полностью перехватывают и повторно процесс вывода дат интерфейса Однако , если вызов функция передается уже вне диапазона ( false
) ввода временных меток
Выводы
Для практических целей и переносимости данных диапазон дат публикации WordPress, по-видимому, равен диапазону 32-битной метки времени Unix и состоит из 1902–2037 годов включительно .
Для любой операции после даты, выходящей за пределы этого диапазона, необходимо провести аудит (64-битный диапазон меток времени Unix, де-факто работающий MySQL или альтернативное хранилище базы данных для значений). Для более дальних диапазонов ( ниже 1000, выше 9999 ), вероятно, потребуется значительное количество пользовательского кода.
Для любой реализации произвольных дат имеет смысл:
- хранить их в MySQL в формате, не подверженном ограничениям базы данных
- процесс в PHP с использованием полностью настраиваемого
Date/Time
кода и / или функций WordPress, которые не подвержены влиянию ограничений на временные метки Unix
Код испытательный стенд
Следующий код и подобранный набор лет использовались для исследования выше и проверки выводов:
require ABSPATH . '/wp-admin/includes/post.php';
$timestamp_size_info = array(
'PHP_INT_SIZE' => PHP_INT_SIZE,
'PHP_INT_MAX' => number_format( PHP_INT_MAX ),
'min timestamp' => date( DATE_ISO8601, - PHP_INT_MAX ),
'zero timestamp' => date( DATE_ISO8601, 0 ),
'max timestamp' => date( DATE_ISO8601, PHP_INT_MAX ),
);
r( $timestamp_size_info );
// hand picked set of years to test for assorted limits
$years = array(
'negative' => - 1,
'zero' => 0,
'one' => 1,
'wp min' => 100,
'mysql first' => 1000,
'before unix' => 1899,
'unix first' => 1902,
'current' => 2013,
'unix last' => 2037,
'after unix' => 2039,
'mysql last, wp max' => 9999,
'after checkdate' => 33000,
);
// simulates form submission data
$post = array(
'post_type' => 'post', // shut notice
'edit_date' => 1,
'aa' => 1,
'mm' => '01',
'jj' => '01',
'hh' => '00',
'mn' => '00',
'ss' => '00',
);
// add_filter( 'wp_checkdate', '__return_true' );
foreach ( $years as $name => $year ) {
$post['aa'] = $year;
$translated = _wp_translate_postdata( false, $post );
if ( is_wp_error( $translated ) ) { // wp_checkdate() failed
r( array( 'year' => $year . " ({$name})", 'translated valid' => false ) );
}
else {
$post_date = $translated['post_date'];
$post_date_gmt = $translated['post_date_gmt'];
$translated_valid = (string) $year == substr( $post_date, 0, strpos( $post_date, '-' ) );
$mysql2date = mysql2date( DATE_ISO8601, $post_date );
$mysql2date_valid = (string) $year == substr( $mysql2date, 0, strpos( $mysql2date, '-' ) );
r( array(
'year' => $year . " ({$name})",
'post_date' => $post_date,
'translated valid' => $translated_valid,
'post_date_gmt' => $post_date_gmt,
'mysql2date' => $mysql2date,
'from sql valid' => $mysql2date_valid,
) );
}
}