XML-RPC

praktyczne czary

Krzysiek Dróżdż
krzysiek@wpmagus.pl
WPmagus.pl

Od tego się zaczęło

czyli… "czy dałoby się…"

Założenia początkowe

Jeden serwis "Matka"

Wiele serwisów "Dzieci" (to też WordPressy)

Kilka minut opóźnienia

i inne drobne szczególiki

Zaciągać czy wypychać?

Gdyby zaciągać

Każde "dziecko" odpytuje co parę minut "matkę"

Musimy nauczyć "dzieci" odpytywać

Czyli wypychać

Ale jak?

Wtyczka, JSON API, XML-RPC, …

XML-RPC

Od wersji 3.5 jest domyślnie włączone

Jest dość wydajne (requesty szybsze niż WordPress)

Jest używane, więc pewnie działa

Rozbijmy to na składowe

Wysyłanie wpisu do "dzieci"

Sprawdź stan wpisu opublikowanego przez "dziecko"

Odśwież wpis

Wysyłanie wpisu


$client = new WP_HTTP_IXR_CLIENT( $url .'/xmlrpc.php' );
$result = $client->query( 'wp.newPost', array(0, $login, $password,
    array(
        'post_status'   => $post->post_status,
        'post_type'     => $post->post_type,
        'post_title'    => $post->post_title,
        ...
        'post_date_gmt' => new IXR_Date( strtotime($post->post_date_gmt) ),
        'sticky'        => is_sticky($post->ID),
        'terms_names'   => array(
            'category'  => $this->get_post_terms($post->ID, 'category'),
            'post_tag'  => $this->get_post_terms($post->ID, 'post_tag'),
        ),
        'custom_fields' => $this->get_post_custom_fields($post->ID),
    )
) );
if ( $result ) return $client->getResponse();  // id wstawionego wpisu
						

Pobieranie zdalnego wpisu


$client = new WP_HTTP_IXR_CLIENT( $url .'/xmlrpc.php' );

$result = $client->query( 'wp.getPost', array(
    0,
    $login,
    $password,
    $post_id
) );

if ( $result )
    return $client->getResponse();  // wpis
						

Odświeżanie wpisu


$client = new WP_HTTP_IXR_CLIENT( $url .'/xmlrpc.php' );
$result = $client->query( 'wp.editPost', array(0, $login, $password,
    $remote_post_id,
    array(
        'ID'            => $remote_post_id,
        'post_status'   => $post->post_status,
        ...
        'post_modified_gmt' => new IXR_Date( strtotime($post->post_modified_gmt) ),
        'terms_names'   => array(
            'category'  => $this->get_post_terms($post->ID, 'category'),
            'post_tag'  => $this->get_post_terms($post->ID, 'post_tag'),
        ),
        'custom_fields' =>
                $this->get_post_CFs($post->ID, $remote_post['custom_fields']),
    )
) );
						

Złóżmy to w całość

Podpinamy się pod filtr post_save


if ( wpis był już wysłany ) {
    pobierz zdalny wpis
    if ( zdalny nie był modyfikowany ) {
        odśwież zdalny wpis
    }
} else {
    wyślij wpis i zapisz ID zdalnego
}
						

Gotowe?

Co jeśli:

  • "dziecko" nie odpowie
  • "dzieci" będzie dużo

Kolejka zadań

Wysłanie wpisu do wszystkich "dzieci" może potrwać

W post_save zapisujemy jedynie zadania do wykonania później

Scheduler / WP Cron

Ustawiamy zadanie do wykonania co k-minut

Za każdym razem pobieramy najnowsze taski z kolejki i je wykonujemy

Po wykonaniu każdego taska, zapamiętujemy jako wykonane

WP Cron - blokuj wiele jednocześnie

WP Cron może próbować wykonać wiele instancji jednocześnie

Czyli mógłby wysłać dany wpis kilka razy

Transienty na ratunek

transient - czyli zmienna tymczasowa

Ustawiamy na początku przetwarzania i usuwamy na koniec

Jeśli przetwarzanie się nie skończy - to transient i tak się odblokuje


if ( get_transient( 'nazwa_zmiennej' ) )
    nic nie rób
set_transient( 'nazwa_zmiennej', '1', 20*60 );
przetwarzanie
delete_transient( 'nazwa_zmiennej' );
						

XML-RPC - co można zrobić?

Umożliwia operowanie na:

Wpisach, Taksonomiach, Mediach, Komentarzach, Opcjach, Użytkownikach.

http://codex.wordpress.org/XML-RPC_WordPress_API

XML-RPC - zagrożenia

Jest szybsze niż cały WP, więc ułatwia ataki brute force, mające na celu uzyskanie dostępu do strony

Na szczęście można wyłączyć

Całe XML-RPC

add_filter('xmlrpc_enabled', '__return_false');

Poszczególne metody


function remove_xmlrpc_pingback_ping( $methods ) {
   unset( $methods['pingback.ping'] );
   return $methods;
}
add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback_ping' );

Dzięki za uwagę!

Krzysiek Dróżdż
krzysiek@wpmagus.pl
WPmagus.pl