Nie można wybrać starej daty w wordpress

13

Nie mogę ustawić roku poniżej 1899 na stanowisko. Jeśli ustawię rok poniżej 1899, zostanie on automatycznie ustawiony na bieżący rok.

zrzut ekranu

Kupiłem motyw Osi czasu i zapytałem na forum wsparcia. Odpowiedzieli:

To brzmi jak ograniczenie utworzone przez twojego dostawcę usług hostingowych. Nic w temacie nie stoi na przeszkodzie, aby przypisać datę - jak widać, demo zawiera posty z datami z 1400 roku. Spróbuj skontaktować się z dostawcą usług hostingowych i sprawdź, czy mają jakiś wgląd w to, jak to rozwiązać.

Spartanie
źródło
2
A twoje pytanie brzmi: co dokładnie? Istnieją tysiące motywów - to długa szansa, aby założyć, że ktokolwiek znałby zakupiony motyw. Musisz przynajmniej podać odpowiedni kod.
Johannes Pille,
1
Wątpię, że to wina gospodarza. Zakładam, że chodzi o wartość zapisaną w bazie danych. Włącz WP_DEBUGi edytuj komunikat błędu w swoim pytaniu. Mogłem tak wyglądać, ale link do działającej wersji omawianego motywu też nie jest zbyt pomocny.
Johannes Pille,
1
To jest uzasadnione pytanie. To nie jest związane z tematem. Mogę odtworzyć ten problem. Zobacz ten animowany zrzut ekranu .
fuxia
1
Ten sam problem z 1900 i 1901, ale 1902 działa ;-)
pan
1
Mogę to odtworzyć, przy okazji, że są problemy również powyżej zakresu datownika Unix (2038). PHP 5.4 na Win7x64
Rarst

Odpowiedzi:

10

To nie jest tak naprawdę odpowiedź, tylko próba znalezienia konkretnego kontekstu dla tego problemu. Zainstaluj następującą wtyczkę na swojej stronie, spróbuj ustawić trzy daty i dodaj wynik do drugiej <pre>w poniższej tabeli.

/* 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>";
}

Gist of Plugin można sprawdzić tutaj .

OS | Bit systemu operacyjnego | PHP | PHP Bit | MySQL | 999 | 1899 | 2020 | 2039 | użytkownik
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 | ✘ | ✘ | ✔ | ✘ | szorstki
Ubuntu 12.04 | 64 | 5.3.10–1 | 64 | 5.5.32 | ✔ | ✔ | ✔ | ✔ | Pille
CloudLinux | 64 | 5.2.17 | 64 | 5.0.96 | ✔ | ✔ | ✔ | ✔ | Pille
Ubuntu 12.10 | 64 | 5.4.6 | 64 | 5.5.32 | ✔ | ✔ | ✔ | ✔ | Michael Ecklund
CENTOS 5.9 | 32 | 5.3.27 | 32 | 5.5.32 | ✘ | ✘ | ✔ | ✘ | Michael Ecklund
WIN7 | 64 | 5.4.7 | 64 | 5.5.27 | ✘ | ✘ | ✔ | ✘ | kajzer
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 | ✔ | ✔ | ✔ | ✔ | Sascha Krause
Win7SP1 | 64 | 5.3.8 | 64 | 5.5.28 | ✔ | ✔ | ✔ | ✔ | Manuel Sychold
  1. Utwórz nowy post. Zapisz to.
  2. Ustaw datę na 1 stycznia 0999, kliknij Aktualizuj . Czy jest zapisany lub zmieniony na bieżącą datę?
  3. Powtórzyć dla ustawień DATY 1899, 2020a 2039.
  4. Pobierz informacje z danych wyjściowych wtyczki w stopce administratora i zaktualizuj tabelę.
toscho
źródło
7

Pytanie i oczekiwania

Chociaż dosłowna forma tego pytania jest praktyczna w kontekście (rok 1899), jest nieco niejasna w sensie teoretycznym. Ile lat ma lat? Jak daleko w przeszłość chcielibyśmy się posunąć? Co z przyszłością?

Ponieważ WordPress zaczął jako silnik do blogowania, w tym kontekście kontekstowym ewoluował, aby obsługiwać następujący przedział czasu:

  • daty WP istniało (oczywiście, aby móc z niego korzystać)
  • zakres możliwych historycznych postów (domyślnie już w czasach istnienia Internetu)
  • jak najdalej w przyszłość, bez specjalnego wysiłku (pracuj, aż się zepsuje)

Gdy korzystanie z WordPress przekształciło się w aplikacje nie blogujące, takie projekty (zwykle historia i sztuka, jak widziałem w raportach) zaczęły napotykać różne problemy z datami spoza tego zakresu.

Na potrzeby moich badań sformułowałem następujące pytania:

  1. Jakie są dwa najwcześniejsze i ostatnie pełne lata kalendarzowe, których można używać z datami postów WordPress w sposób natywny i niezawodny?
  2. Jakie są nisko wiszące owoce (jeśli występują), aby przedłużyć dostępny zakres poza natywny zasięg?

Ograniczenia platformy

Ponieważ WordPress jest aplikacją PHP i korzysta z MySQL do przechowywania danych, podlega ich ograniczeniom.

MySQL

WordPress przechowuje daty postów w post_datekolumnie DATETIMEtypu w MySQL.

Zgodnie z dokumentacją ten typ obsługuje lata od 1000 do 9999 :

Ten DATETIMEtyp jest używany dla wartości, które zawierają zarówno części daty, jak i godziny. MySQL pobiera i wyświetla DATETIMEwartości w 'YYYY-MM-DD HH:MM:SS'formacie. Obsługiwany zakres jest '1000-01-01 00:00:00'do '9999-12-31 23:59:59'.

Jednak mówi również, że wcześniejsze wartości mogą działać, nie wspominając o późniejszych wartościach:

W przypadku DATE and DATETIMEopisów zakresów „obsługiwane” oznacza, że ​​chociaż wcześniejsze wartości mogą działać, nie ma gwarancji.

Chociaż empirycznie zaobserwowałem wartości poza zakresem działania, jest to anegdota i wypada z naszego stanu niezawodności.

PHP

W programowaniu PHP powszechnie stosowana jest uniksowa reprezentacja datownika. Zgodnie z dokumentacją do naszych celów (PHP 5.2+ i ogólne 32-bitowe środowisko) obsługuje lata (w całości) 1902 do 2037 :

Prawidłowy zakres znacznika czasu to zazwyczaj od Fri, 13 Dec 1901 20:45:54 UTCdo Tue, 19 Jan 2038 03:14:07 UTC. (Są to daty, które odpowiadają minimalnym i maksymalnym wartościom dla 32-bitowej liczby całkowitej ze znakiem). Ponadto nie wszystkie platformy obsługują ujemne znaczniki czasu, dlatego zakres dat może być ograniczony nie wcześniej niż w epoce Uniksa. Oznacza to, że np. Wcześniejsze daty Jan 1, 1970nie będą działać w systemie Windows, niektórych dystrybucjach Linuksa i kilku innych systemach operacyjnych. PHP 5.1.0 i nowsze wersje pokonują jednak to ograniczenie.

Poza tym nowsza Date/Timeobsługa oparta jest na wersji 64-bitowej i ma zakres od około 292 miliardów do 292 miliardów lat , co prawdopodobnie przekracza potrzeby ludzkości w tym czasie.

Ograniczenia WordPress

WordPress wprowadza i dziedziczy pewne dodatkowe ograniczenia w swojej podstawie kodu.

Przepływ danych

Z punktu widzenia podstawowego przepływu pracy użytkownika są przetwarzane dwa powiązane z datą:

  • Wprowadzanie daty w formularzu edycji postu musi być poprawnie przetworzone i zapisane w bazie danych
  • data zapisana w bazie danych musi być poprawnie odczytana i pokazana w interfejsie

Należy pamiętać, że są to technicznie całkowicie różne i niezależne procesy. Jak wyjaśniono dalej, ich zakresy nie nakładają się, a zapisanie prawidłowej daty nie oznacza zdolności do prawidłowego odczytu jej w środowisku WordPress.

Jawne ograniczenia

  • Edytor postów WordPress w admin pozwala na zakres lat, które można przesłać jako datę ogłoszenia, od 100 do 9999
  • _wp_translate_postdata() przetwarza rok (przesłany jako numer odrębny od formularza) i:
    • dezynfekuje go do wartości nieujemnych > 0
    • sprawdza poprawność za pomocą wp_checkdate(), który wywołuje PHP natywny checkdate(), co nakłada limit od 1 do 32767

Domniemane limity

  • strtotime()Funkcja PHP jest używana wiele razy i podlega wyżej wymienionemu znacznikowi czasu Unix, na najniższym poziomie, mysql2date()który wpływa na wszystkie odczyty dat z bazy danych, dziedziczony zakres od 1902 do 2037
  • WordPress wraca do wyrażenia regularnego do analizowania daty get_gmt_from_date(), który oczekuje roku ([0-9]{1,4}), ograniczając go do 1 9999 , silna możliwość podobnego przetwarzania w innych funkcjach, które będą wymagały dokładniejszego audytu kodu

Możliwość obejścia

  • wp_checkdate()ma wp_checkdatefiltr, który pozwala zastąpić tę kontrolę sprawdzania poprawności
  • wyjście skierowane do użytkownika końcowego przechodzi przez date_i18n()który ma date_i18nfiltr, teoretycznie pozwala całkowicie przechwycić i ponownie przetworzyć dane wyjściowe do interfejsu, jednak trudne, jeśli funkcja jest już przekazana poza falsewejście znacznika czasu poza zakresem ( )

Wnioski

Ze względów praktycznych i możliwości przenoszenia danych zakres dat publikacji WordPress wydaje się być równy 32-bitowemu znacznikowi czasu Unix i obejmuje lata 1902–2037 włącznie .

W przypadku każdej operacji po dacie poza środowiskiem należy skontrolować środowisko (64-bitowy zakres uniksowych znaczników czasu, de facto działający MySQL lub alternatywna pamięć bazy danych dla wartości). W przypadku dalszych zakresów ( poniżej 1000, powyżej 9999 ) prawdopodobnie wymagane będą znaczne ilości niestandardowego kodu.

W przypadku dowolnej realizacji dowolnych dat sensowne jest:

  • przechowuj je w MySQL w formacie niepodlegającym ograniczeniom bazy danych
  • proces w PHP przy użyciu całkowicie niestandardowego Date/Timekodu i / lub kontrolowanych funkcji WordPress, na które nie mają wpływu ograniczenia uniksowego znacznika czasu

Łóżko testowe do kodu

Poniższy kod i ręcznie wybrany zestaw lat zostały wykorzystane do powyższych badań i testowania wniosków:

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
źródło
+1 Pozostało tylko pytanie: co to jest r()?
kaiser
1
@kaiser php-ref , zastąp wybraną funkcją zrzutu :)
Rarst