SyncCode I3 rpc.php
From MWWiki
Back to WordPress Synchronizer
<?php session_start(); include_once('common.inc.php'); // first, set up the function cache of callables $cache = array('load', 'merge', 'sync' ); // initialize the timer if (!isset($_SESSION['time'])) { $_SESSION['time'] = 0; } // this is where all the magic happens // might want to do some processing here so the user can't call, // say, phpinfo() ... if (in_array($_GET['function'], $cache)) { echo $_GET['function']($_GET['argument']); } else { if (!isset($_GET['function'])) { echo 'Error! No argument defined!<br />'; } else { echo 'Error! Undefined argument "' . $_GET['function'] . '".<br />'; } } // ********* FUNCTIONS *********** /** * Loads the latest entry from the specified WordRPC handler. * * The calling script specifies what WordRPC handler is going to process * a request for the latest entry the handler is connected to. Provided * the argument provided is valid, this function returns the ID number * of the latest entry. * * @param class object A reference to the WordRPC object being used. * @return int The ID of the latest entry. */ function load($class) { global $$class; // sanity check if (!isset($$class)) { return 'Error! Invalid argument "' . $class . '" provided to function "load()".<br />'; } // start the timer $retval = ""; $start = time(); // make the request $_SESSION[$class] = $$class->getPostIDs(1); if (count($_SESSION[$class]) == 0) { $retval = 'Error! Blog "' . $class . '" returned 0 results!<br />'; } else { $retval = 'RPC successful. Response from blog "' . $class . '" with ID ' . $_SESSION[$class][0]['postid'] . '.<br />'; } // stop the timer $end = time(); $_SESSION['time'] += $end - $start; // a bit of debugging $cfg = Config::getInstance(); if ($cfg->getValue('debug')) { fb($retval, 'Return value', FirePHP::LOG); fb($_SESSION['time'], 'Current Time Value', FirePHP::LOG); fb($_SESSION[$class][0]['postid'], $class . ' Post ID', FirePHP::LOG); } // finish! return $retval; } /** * Conglomerates the posts together and creates an HTML form of the post IDs * that need to be synchronized to the blog that is lacking posts. * * @return string An HTML string consisting of the form for RPC to submit the entries. */ function merge() { // WordRPC objects global $local, $remote; $retval = ""; // start the timer $start = time(); // entry IDs $localID = $_SESSION['local'][0]['postid']; $remoteID = $_SESSION['remote'][0]['postid']; // check the entry IDs // 1) if they are equal, there's nothing to be done! // 2) if they are not equal, some synchronizing needs to happen if ($localID == $remoteID) { // case 1 $retval = 'No entries to synchronize! Both blogs up to date.<br />'; } else { // case 2 // the blog with the latest entries $from = ($localID > $remoteID ? $from = $local : $from = $remote); // get all the missing posts $posts = $from->getPostIDs(abs($localID - $remoteID)); $posts = requestedPosts($posts, $localID, $remoteID); // make everything in a nice printable format $retval = makeReadable($posts); // debugging $cfg = Config::getInstance(); if ($cfg->getValue('debug')) { $numPosts = count($posts); fb($numPosts, 'Number of posts', FirePHP::LOG); $printable = array(); for ($i = 0; $i < $numPosts; $i++) { $printable[$i] = $posts[$i]['postid']; } fb($printable, 'Posts', FirePHP::LOG); fb($retval, 'Readable format', FirePHP::LOG); } } // stop the timer $end = time(); $_SESSION['time'] += $end - $start; $retval .= '<b>Operation took ' . $_SESSION['time'] . ' seconds.</b><br />'; cleanup(); return $retval; } /** * This method posts all the selected entries via RPC to the blog requiring entry * updates. This is determined by querying both RPC connections for their latest * post ID, and the blog with the lesser ID number is considered in need of updating. * * @return string An HTML string consisting of the results of the RPC submission. */ function sync() { global $local, $remote; // first, a little sanity check if (!isset($_POST['elements'])) { die('No posts found for synchronizing!'); } // start the timer $start = time(); // set up the blogs $localID = $local->getPostIDs(1); $remoteID = $remote->getPostIDs(1); if ($localID < $remoteID) { $to = $local; $from = $remote; } else { $to = $remote; $from = $local; } // pick up the entries $retval = ""; $prev = -1; for ($i = ($_POST['elements'] - 1); $i >= 0; $i--) { $ID = $_POST['id_' . $i]; // do we need a few dummy entries? if ($prev > -1 && $prev < ($ID - 1)) { $prev = dummyEntries($prev, $ID); } // get the entire post to send $entry = $from->getPost($ID); // submit the post $value = $to->newPost($entry); if (is_array($value)) { die( '<b>Error!</b><br />' . $value['faultCode'] . ': ' . $value['faultString'] . '<br />'); } // print the result $retval .= 'Entry ' . $value . ' sent!<br />'; // update the previous counter $prev = $entry; } $retval .= '<br /><b>Finished in ' . (time() - $start) . ' seconds! :)</b></br />'; return $retval; } /** * This function handles looping on creation and deletion of dummy entries, * in order to truly have the remote server mirror the local one. This can * be computationally expensive; there will be wait times involved for the user. * * @param previous An integer indicating the last successful postID synchronized. * @param current An integer indicating the current postID waiting to be synchronized. * @return An integer indicating the last successful postID - should be (current - 1). */ function dummyEntries($previous, $current, $rpc) { /* loop until we reach our goal */ while ($previous < ($current - 1)) { $struct['post_title'] = "DUMMY"; $struct['description'] = "DUMMY POST! LOLZ"; /* insert the post */ $id = $rpc->newPost($struct); if (is_array($id)) { /* crap on a stick */ die( '<b>Error posting dummy entry!</b><br />' . $id['faultCode'] . ': ' . $id['faultString'] . '<br />'); } /* update the count */ $previous = $id; /* now, delete it */ $id = $rpc->deletePost($id); if (is_array($id)) { /* shucks */ die( '<b>Error deleting dummy post!</b><br />' . $id['faultCode'] . ': ' . $id['faultString'] . '<br />'); } } /* end while loop */ /* return the current previous count */ return $previous; } /** * Unsets all session variables and destroys the current session. */ function cleanup() { unset($_SESSION['local']); unset($_SESSION['remote']); unset($_SESSION['time']); session_destroy(); } /** * Trims the array of entries returned by XMLRPC to only include those entries * with IDs between $first and $last. * * @param $entries array The array of entries (response from XMLRPC) * @param $local int The ID corresponding to the last local entry * @param $remote int The ID corresponding to the last remote entry * @return array A subset of the $entries array: ($first, $last] */ function requestedPosts($entries, $local, $remote) { $first = $local; $last = $remote; // make sure $first <= $last if ($first > $last) { $last = $local; $first = $remote; } $retval = array(); $length = count($entries); $numElems = 0; // do the loop for ($i = 0; $i < $length; $i++) { if ($entries[$i]['postid'] > $first && $entries[$i]['postid'] <= $last) { $retval[$numElems++] = $entries[$i]; } } // finished return $retval; } /** * Converts the posts into an HTML form that can be read through AJAX and * submitted. * * @param $posts array The array of posts. * @return string The posts in HTML. */ function makeReadable($posts) { $numPosts = count($posts); $retval = '<form action="javascript:POSTrequest(' . $numPosts . ');" ' . 'method="post"><input type="submit" value="Post Entries" />' . "\n"; for ($i = 0; $i < $numPosts; $i++) { $retval .= '<input type="hidden" name="id_' . $i . '" value="' . $posts[$i]['postid'] . '" />'; $retval .= '<label>' . date('j M Y, g:ia', $posts[$i]['dateCreated']->timestamp) . ' - '; $retval .= (isset($posts[$i]['title']) && $posts[$i]['title'] != '' ? htmlentities($posts[$i]['title']) : '<i>[no subject]</i>'); $retval .= '</label><br />' . "\n"; } $retval .= '</form>'; // finished return $retval; } ?>
