Невозможно выбрать старую дату в WordPress

13

Я не могу установить год ниже 1899 для поста. Если я установлю год ниже 1899, он будет установлен на текущий год автоматически.

Скриншот

Я купил тему Timeline и спросил на их форуме поддержки. Они ответили:

Это звучит как ограничение, созданное вашим хостинг-провайдером. Ничто в теме не препятствует назначенной вами дате - как вы можете видеть, в демоверсии есть записи с датами 1400-х годов. Попробуйте связаться с вашим хостинг-провайдером и посмотреть, есть ли у них понимание того, как решить эту проблему.

Спартанцы
источник
2
И твой вопрос, что именно? Есть тысячи тем - это длинный шанс предположить, что кто-нибудь узнает тему, которую вы купили. Вы должны будете по крайней мере предоставить соответствующий код.
Йоханнес Пилле
1
Я сомневаюсь, что это вина хостера. Я полагаю, это касается значения, сохраненного в базе данных. Включите WP_DEBUGи отредактируйте сообщение об ошибке в свой вопрос. Я мог бы заставить это казаться таким, но ссылка на рабочую версию рассматриваемой темы на самом деле тоже не сильно помогает.
Йоханнес Пилле
1
Это законный вопрос. Это не связано с темой. Я могу воспроизвести эту проблему. Смотрите этот анимированный снимок экрана .
Fuxia
1
Та же проблема с 1900 и 1901 годами, но 1902 работает ;-)
birgire
1
Я могу воспроизвести это, кстати, есть проблемы выше диапазона отметок времени Unix (2038). PHP 5.4 на Win7x64
Rarst

Ответы:

10

На самом деле это не ответ, а попытка найти конкретный контекст для этой проблемы. Пожалуйста, установите следующий плагин на свой сайт, попробуйте установить три даты и добавить свой результат ко второму <pre>в таблице ниже.

/* Plugin Name: WPSE Sysinfo */
add_action( 'admin_footer', 'wpse_sysinfo' );
function wpse_sysinfo() {

    $bit         = 4 === PHP_INT_SIZE ? 32 : 64; // PHP version, not OS!
    $php_version = PHP_VERSION;
    $db_version  = $GLOBALS['wpdb']->db_version();

    print "<pre>$bit | $php_version | $db_version</pre>";
}

Суть плагина можно проверить здесь .

ОС | ОС бит | PHP | PHP Бит | MySQL | 999 | 1899 | 2020 | 2039 | пользователь
WIN7 | 64 | 5.4.4 | ?? | 5.5.25 | ✘ | ✘ | ✔ | ✘ | toscho
Linux | ?? | 5.3.18-nmm1 | ?? | 5.1.70 | ✔ | ✔ | ✔ | ✔ | toscho
CentOS 6 | 64 | 5.5.4 | ?? | 5.0.95 | ✔ | ✔ | ✔ | ✔ | toscho
WIN7 | 64 | 5.4.15 | 32 | 5.5.31 | ✘ | ✘ | ✔ | ✘ | rarst
Ubuntu 12.04 | 64 | 5.3.10-1 | 64 | 5.5.32 | ✔ | ✔ | ✔ | ✔ | Пиль
CloudLinux | 64 | 5.2.17 | 64 | 5.0.96 | ✔ | ✔ | ✔ | ✔ | Пиль
Ubuntu 12.10 | 64 | 5.4.6 | 64 | 5.5.32 | ✔ | ✔ | ✔ | ✔ | Майкл Эклунд
CENTOS 5.9 | 32 | 5.3.27 | 32 | 5.5.32 | ✘ | ✘ | ✔ | ✘ | Майкл Эклунд
WIN7 | 64 | 5.4.7 | 64 | 5.5.27 | ✘ | ✘ | ✔ | ✘ | кайзер
OSX 10.7.5 | 64 | 5.3.6 | 64 | 5.5.9 | ✔ | ✔ | ✔ | ✔ | GhostToast
Centos 6.4 | 64 | 5.4.17 | 32 | 5.1.59 | ✘ | ✘ | ✔ | ✘ | birgire
Debian 6 | 64 | 5.4.19 | 64 | 5.1.66 | ✘ | ✘ | ✔ | ✘ | birgire
WIN7 | 64 | 5.5.0 | 64 | 5.5.22 | ✘ | ✘ | ✔ | ✘ | GM
OSX 10.7.4 | 64 | 5.3.6 | 64 | 5.5.9 | ✔ | ✔ | ✔ | ✔ | brasofilo
CentOS 5 | 64 | 5.3.22 | 64 | 5.1.68 | ✔ | ✔ | ✔ | ✔ | brasofilo
Mac 10.8.5 | 64 | 5.3.26 | 64 | 5.5.25 | ✔ | ✔ | ✔ | ✔ | flentini
WIN7 | 64 | 5.3.27 | 64 | 5.5.31 | ✔ | ✔ | ✔ | ✔ | Саша Краузе
Win7SP1 | 64 | 5.3.8 | 64 | 5.5.28 | ✔ | ✔ | ✔ | ✔ | Мануэль Сихольд
  1. Создать новый пост. Сохрани это.
  2. Установите дату 1 января 0999, нажмите « Обновить» . Сохранено или изменено на текущую дату?
  3. Повторите эти действия для настройки даты для 1899, 2020и 2039.
  4. Возьмите информацию из вывода плагина в нижнем колонтитуле администратора и обновите таблицу.
toscho
источник
7

Вопрос и ожидания

Хотя буквальная форма этого вопроса практична в контексте (1899 год), в теоретическом смысле она немного расплывчата. Сколько лет старому? Как далеко в прошлое , мы могли бы хотеть пойти? Как насчет будущего?

Так как WordPress начинал как движок блогов, в этом контексте он развивался, чтобы обрабатывать следующие промежутки времени:

  • даты WP существовали (очевидно, чтобы иметь возможность использовать его)
  • диапазон возможных исторических сообщений (неявно еще в существовании Интернета)
  • как можно дальше в будущее без особых усилий (работайте до тех пор, пока оно не сломается)

Поскольку использование WordPress превратилось в приложения для ведения блогов, такие проекты (как правило, история и искусство, как я видел из отчетов) начали сталкиваться с различными проблемами с датами за пределами этого диапазона.

Для целей моего исследования я сформулировал следующие вопросы:

  1. Какие два самых ранних и последних полных календарных года можно использовать с датами публикации WordPress изначально и надежно?
  2. Что такое низко висящие фрукты (если таковые имеются), чтобы расширить доступный диапазон за пределы родного диапазона?

Ограничения платформы

Поскольку 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,
        ) );
    }
}
Rarst
источник
+1 Остался только вопрос: что это r()?
Кайзер
1
@kaiser php-ref , замените функцию выбора дампа :)
Rarst