function registerEventHooks() { \Idno\Core\site()->syndication()->registerService('soundcloud', function () { return $this->hasSoundcloud(); }, array('media')); \Idno\Core\site()->addEventHook('user/auth/success', function (\Idno\Core\Event $event) { if ($this->hasSoundcloud()) { if (is_array(\Idno\Core\site()->session()->currentUser()->soundcloud)) { foreach (\Idno\Core\site()->session()->currentUser()->soundcloud as $username => $details) { if (!in_array($username, ['username', 'access_token'])) { \Idno\Core\site()->syndication()->registerServiceAccount('soundcloud', $username, $username); } } } } }); // Push "media" to Soundcloud \Idno\Core\site()->addEventHook('post/media/soundcloud', function (\Idno\Core\Event $event) { $eventdata = $event->data(); $object = $eventdata['object']; if ($attachments = $object->getAttachments()) { foreach ($attachments as $attachment) { if ($this->hasSoundcloud()) { if (!empty($eventdata['syndication_account'])) { $soundcloudAPI = $this->connect($eventdata['syndication_account']); $user_details = \Idno\Core\site()->session()->currentUser()->soundcloud[$eventdata['syndication_account']]; if (!empty($user_details['username'])) { $name = $user_details['username']; } } else { $soundcloudAPI = $this->connect(); $user_details = \Idno\Core\site()->session()->currentUser()->soundcloud['access_token']; } if (empty($name)) { $name = 'SoundCloud'; } if ($soundcloudAPI && !empty($user_details)) { $soundcloudAPI->setAccessToken($user_details['access_token']); if ($bytes = \Idno\Entities\File::getFileDataFromAttachment($attachment)) { $media = ''; $filename = tempnam(sys_get_temp_dir(), 'knownsoundcloud') . '.' . pathinfo($attachment['url'], PATHINFO_EXTENSION); file_put_contents($filename, $bytes); if (version_compare(phpversion(), '5.5', '>=')) { $media = new \CURLFile($filename); if (!empty($attachment['mime_type'])) { $media->setMimeType($attachment['mime_type']); } if (!empty($attachment['filename'])) { $media->setPostFilename($attachment['filename']); } } else { $media .= "@{$filename}"; //;type=" . $attachment['mime_type'] . ';filename=' . $attachment['filename']; } } $message = strip_tags($object->getDescription()); $message .= "\n\nOriginal: " . $object->getURL(); try { $track = json_decode($soundcloudAPI->post('tracks', array('track[title]' => $object->getTitle(), 'track[asset_data]' => $media, 'track[description]' => $message))); if (!empty($track->permalink_url)) { $result['id'] = $track->id; $object->setPosseLink('soundcloud', $track->permalink_url, $name); $object->save(); } } catch (\Exception $e) { \Idno\Core\site()->session()->addMessage('Could not post sound to SoundCloud: ' . $e->getMessage()); } @unlink($filename); } } } } }); }
/** * Prepares an archive containing all of this site's data. * @return string */ static function exportToFolder($dir = false) { set_time_limit(0); // Switch off the time limit for PHP site()->currentPage()->setPermalink(true); // Prepare a unique name for the archive $name = md5(time() . rand(0, 9999) . site()->config()->getURL()); // If $folder is false or doesn't exist, use the temporary directory and ensure it has a slash on the end of it if (!is_dir($dir)) { $dir = site()->config()->getTempDir(); } // Make the temporary directory, or fail out if (!@mkdir($dir . $name)) { return false; } $json_path = $dir . $name . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR; if (!@mkdir($json_path)) { return false; } $html_path = $dir . $name . DIRECTORY_SEPARATOR . 'html' . DIRECTORY_SEPARATOR; if (!@mkdir($html_path)) { return false; } $file_path = $dir . $name . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR; if (!@mkdir($file_path)) { return false; } if (!@mkdir($file_path . 'readable', 0777, true)) { return false; } if (!@mkdir($file_path . 'uploads', 0777, true)) { return false; } // If we've made it here, we've created a temporary directory with the hash name $config = array('url' => site()->config()->getURL(), 'title' => site()->config()->getTitle()); file_put_contents($dir . $name . DIRECTORY_SEPARATOR . 'known.json', json_encode($config)); $all_in_one_json = ''; // Let's export everything. $fields = array(); $query_parameters = array('entity_subtype' => array('$not' => array('$in' => array('Idno\\Entities\\ActivityStreamPost')))); $collection = 'entities'; if ($results = site()->db()->getRecords($fields, $query_parameters, 99999, 0, $collection)) { foreach ($results as $id => $row) { $object = site()->db()->rowToEntity($row); if (!empty($object->_id) && $object instanceof Entity) { $object_name = $object->_id; $attachments = $object->attachments; if (empty($attachments)) { $attachments = []; } foreach (['thumbnail', 'thumbnail_large'] as $thumbnail) { if (!empty($object->{$thumbnail})) { if (preg_match('/file\\/([a-zA-Z0-9]+)\\//', $object->{$thumbnail}, $matches)) { $attachments[] = ['url' => $object->{$thumbnail}, '_id' => $matches[1]]; } } } if (!empty($attachments)) { foreach ($attachments as $key => $attachment) { if ($data = File::getFileDataFromAttachment($attachment)) { $filename = $attachment['_id']; $id = $attachment['_id']; if ($ext = pathinfo($attachment['url'], PATHINFO_EXTENSION)) { $filename .= '.' . $ext; } if (!empty($attachment['mime-type'])) { $mime_type = $attachment['mime-type']; } else { $mime_type = 'application/octet-stream'; } file_put_contents($file_path . 'readable/' . $filename, $data); $attachments[$key]['url'] = '../files/' . site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1] . '/' . $id[2] . '/' . $id[3] . '/' . $id . '.file'; //$filename; $data_file = $file_path . 'uploads/' . \Idno\Core\site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1] . '/' . $id[2] . '/' . $id[3] . '/' . $id . '.data'; foreach (array($file_path . 'uploads/' . \Idno\Core\site()->config()->pathHost(), $file_path . \Idno\Core\site()->config()->pathHost() . '/' . $id[0], $file_path . 'uploads/' . \Idno\Core\site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1], $file_path . 'uploads/' . \Idno\Core\site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1] . '/' . $id[2], $file_path . 'uploads/' . \Idno\Core\site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1] . '/' . $id[2] . '/' . $id[3]) as $up_path) { if (!is_dir($up_path)) { $result = mkdir($up_path, 0777, true); } } file_put_contents($file_path . 'uploads/' . site()->config()->pathHost() . '/' . $id[0] . '/' . $id[1] . '/' . $id[2] . '/' . $id[3] . '/' . $id . '.file', $data); file_put_contents($data_file, json_encode(['filename' => $filename, 'mime_type' => $mime_type])); } } $object->attachments = $attachments; } $activityStreamPost = new \Idno\Entities\ActivityStreamPost(); if ($owner = $object->getOwner()) { $activityStreamPost->setOwner($owner); $activityStreamPost->setActor($owner); $activityStreamPost->setTitle(sprintf("%s posted %s", $owner->getTitle(), $object->getTitle())); } $activityStreamPost->setVerb('post'); $activityStreamPost->setObject($object); $json_object = json_encode($object); file_put_contents($json_path . $object_name . '.json', $json_object); $all_in_one_json[] = json_decode($json_object); if (is_callable(array($object, 'draw'))) { //file_put_contents($html_path . $object_name . '.html', $activityStreamPost->draw()); file_put_contents($html_path . $object_name . '.html', $object->draw()); } //unset($results[$id]); //unset($object); gc_collect_cycles(); // Clean memory } } } if ($exported_records = \Idno\Core\site()->db()->exportRecords()) { if (site()->config()->database == 'mysql' || site()->config()->database == 'postgres') { $export_ext = 'sql'; } else { $export_ext = 'json'; } file_put_contents($dir . $name . DIRECTORY_SEPARATOR . 'exported_data.' . $export_ext, $exported_records); } file_put_contents($dir . $name . DIRECTORY_SEPARATOR . 'entities.json', json_encode($all_in_one_json)); // As we're successful, return the unique name of the archive return $dir . $name; }
function registerEventHooks() { \Idno\Core\Idno::site()->syndication()->registerService('twitter', function () { return $this->hasTwitter(); }, array('note', 'article', 'image', 'media', 'rsvp', 'bookmark')); \Idno\Core\Idno::site()->addEventHook('user/auth/success', function (\Idno\Core\Event $event) { if ($this->hasTwitter()) { $twitter = \Idno\Core\Idno::site()->session()->currentUser()->twitter; if (is_array($twitter)) { foreach ($twitter as $username => $details) { if (!in_array($username, ['user_token', 'user_secret', 'screen_name'])) { \Idno\Core\Idno::site()->syndication()->registerServiceAccount('twitter', $username, $username); } } if (array_key_exists('user_token', $twitter)) { \Idno\Core\Idno::site()->syndication()->registerServiceAccount('twitter', $twitter['screen_name'], $twitter['screen_name']); } } } }); // Activate syndication automatically, if replying to twitter \Idno\Core\Idno::site()->addEventHook('syndication/selected/twitter', function (\Idno\Core\Event $event) { $eventdata = $event->data(); if (!empty($eventdata['reply-to'])) { $replyto = $eventdata['reply-to']; if (!is_array($replyto)) { $replyto = [$replyto]; } foreach ($replyto as $url) { if (strpos(parse_url($url)['host'], 'twitter.com') !== false) { $event->setResponse(true); } } } }); // Push "notes" to Twitter \Idno\Core\Idno::site()->addEventHook('post/note/twitter', function (\Idno\Core\Event $event) { $eventdata = $event->data(); if ($this->hasTwitter()) { $object = $eventdata['object']; if (!empty($eventdata['syndication_account'])) { $twitterAPI = $this->connect($eventdata['syndication_account']); } else { $twitterAPI = $this->connect(); } $status_full = trim($object->getDescription()); $status = preg_replace('/<[^\\>]*>/', '', $status_full); //strip_tags($status_full); $status = str_replace("\r", '', $status); // Add link to original post, if IndieWeb references have been requested if (!substr_count($status, \Idno\Core\Idno::site()->config()->host) && \Idno\Core\Idno::site()->config()->indieweb_reference) { $status .= ' ' . $object->getShortURL(); } // Get links at this stage preg_match_all('/((ht|f)tps?:\\/\\/[^\\s\\r\\n\\t<>"\'\\(\\)]+)/i', $status_full, $matches); global $url_matches; // ugh preg_match_all('/((ht|f)tps?:\\/\\/[^\\s\\r\\n\\t<>"\'\\(\\)]+)/i', $status, $url_matches); $count_status = preg_replace('/((ht|f)tps?:\\/\\/[^\\s\\r\\n\\t<>"\'\\(\\)]+)/i', '12345678901234567890123', $status); $count_status = trim($count_status); if (mb_strlen($count_status) > 140) { $count_status = substr($count_status, 0, 117); if ($count_status[mb_strlen($count_status) - 1] != ' ') { $count_status = substr($count_status, 0, strrpos($count_status, ' ')); } $count_status = preg_replace_callback('/12345678901234567890123/', function ($callback) { global $status_update_url_num; global $status_url_matches; if (empty($status_update_url_num)) { $status_update_url_num = 0; } if (!empty($status_url_matches[0][$status_update_url_num])) { return $status_url_matches[0][$status_update_url_num]; } $status_update_url_num++; return ''; }, $count_status); $count_status .= ' .. ' . $object->getSyndicationURL(); $status = $count_status; } $status = preg_replace('/[ ]{2,}/', ' ', $status); $params = array('status' => trim($status)); // Find any Twitter status IDs in case we need to mark this as a reply to them if (!empty($matches[0])) { foreach ($matches[0] as $match) { if (parse_url($match, PHP_URL_HOST) == 'twitter.com') { preg_match('/[0-9]{8,}/', $match, $status_matches); $params['in_reply_to_status_id'] = $status_matches[0]; } } } $response = $twitterAPI->request('POST', $twitterAPI->url('1.1/statuses/update'), $params); if (!empty($twitterAPI->response['response'])) { if ($json = json_decode($twitterAPI->response['response'])) { if (!empty($json->id_str)) { $object->setPosseLink('twitter', 'https://twitter.com/' . $json->user->screen_name . '/status/' . $json->id_str, '@' . $json->user->screen_name); $object->save(); } else { \Idno\Core\Idno::site()->logging()->log("Nothing was posted to Twitter: " . var_export($json, true)); \Idno\Core\Idno::site()->logging()->log("Twitter tokens: " . var_export(\Idno\Core\Idno::site()->session()->currentUser()->twitter, true)); } } else { \Idno\Core\Idno::site()->logging()->log("Bad JSON from Twitter: " . var_export($json, true)); } } } }); // Function for articles, RSVPs etc $article_handler = function (\Idno\Core\Event $event) { if ($this->hasTwitter()) { $eventdata = $event->data(); $object = $eventdata['object']; if (!empty($eventdata['syndication_account'])) { $twitterAPI = $this->connect($eventdata['syndication_account']); } else { $twitterAPI = $this->connect(); } $status = $object->getTitle(); if (mb_strlen($status) > 110) { // Trim status down if required $status = substr($status, 0, 106) . ' ...'; } $status .= ' ' . $object->getSyndicationURL(); $params = array('status' => $status); $response = $twitterAPI->request('POST', $twitterAPI->url('1.1/statuses/update'), $params); if (!empty($twitterAPI->response['response'])) { if ($json = json_decode($twitterAPI->response['response'])) { if (!empty($json->id_str)) { $object->setPosseLink('twitter', 'https://twitter.com/' . $json->user->screen_name . '/status/' . $json->id_str, '@' . $json->user->screen_name); $object->save(); } else { \Idno\Core\Idno::site()->logging()->log("Nothing was posted to Twitter: " . var_export($json, true)); } } else { \Idno\Core\Idno::site()->logging()->log("Bad JSON from Twitter: " . var_export($json, true)); } } } }; // Push "articles" and "rsvps" to Twitter \Idno\Core\Idno::site()->addEventHook('post/article/twitter', $article_handler); \Idno\Core\Idno::site()->addEventHook('post/rsvp/twitter', $article_handler); \Idno\Core\Idno::site()->addEventHook('post/bookmark/twitter', $article_handler); // Push "media" to Twitter \Idno\Core\Idno::site()->addEventHook('post/media/twitter', function (\Idno\Core\Event $event) { if ($this->hasTwitter()) { $eventdata = $event->data(); $object = $eventdata['object']; if (!empty($eventdata['syndication_account'])) { $twitterAPI = $this->connect($eventdata['syndication_account']); } else { $twitterAPI = $this->connect(); } $status = $object->getTitle(); if (mb_strlen($status) > 110) { // Trim status down if required $status = substr($status, 0, 106) . ' ...'; } $status .= ' ' . $object->getURL(); $params = array('status' => $status); $response = $twitterAPI->request('POST', $twitterAPI->url('1.1/statuses/update'), $params); if (!empty($twitterAPI->response['response'])) { if ($json = json_decode($twitterAPI->response['response'])) { if (!empty($json->id_str)) { $object->setPosseLink('twitter', 'https://twitter.com/' . $json->user->screen_name . '/status/' . $json->id_str, '@' . $json->user->screen_name); $object->save(); } else { \Idno\Core\Idno::site()->logging()->log("Nothing was posted to Twitter: " . var_export($json, true)); } } else { \Idno\Core\Idno::site()->logging()->log("Bad JSON from Twitter: " . var_export($json, true)); } } } }); // Push "images" to Twitter \Idno\Core\Idno::site()->addEventHook('post/image/twitter', function (\Idno\Core\Event $event) { if ($this->hasTwitter()) { $eventdata = $event->data(); $object = $eventdata['object']; if (!empty($eventdata['syndication_account'])) { $twitterAPI = $this->connect($eventdata['syndication_account']); } else { $twitterAPI = $this->connect(); } $status = $object->getTitle(); if ($status == 'Untitled') { $status = ''; } if (mb_strlen($status) > 110) { // Trim status down if required $status = substr($status, 0, 106) . ' ...'; } // Let's first try getting the thumbnail if (!empty($object->thumbnail_id)) { if ($thumb = (array) \Idno\Entities\File::getByID($object->thumbnail_id)) { $attachments = array($thumb['file']); } } // No? Then we'll use the main event if (empty($attachments)) { $attachments = $object->getAttachments(); } if (!empty($attachments)) { foreach ($attachments as $attachment) { if ($bytes = \Idno\Entities\File::getFileDataFromAttachment($attachment)) { $media = array(); $filename = tempnam(sys_get_temp_dir(), 'idnotwitter'); file_put_contents($filename, $bytes); $media['media_data'] = base64_encode(file_get_contents($filename)); $params = $media; $response = $twitterAPI->request('POST', 'https://upload.twitter.com/1.1/media/upload.json', $params, true, true); \Idno\Core\Idno::site()->logging()->log($response); $json = json_decode($twitterAPI->response['response']); if (isset($json->media_id_string)) { $media_id[] = $json->media_id_string; error_log("Twitter media_id : " . $json->media_id); } else { /*{"errors":[{"message":"Sorry, that page does not exist","code":34}]}*/ if (isset($json->errors)) { $message[] = $json->errors; $twitter_error = $message['message'] . " (code " . $message['code'] . ")"; } \Idno\Core\Idno::site()->session()->addMessage("We couldn't upload photo to Twitter. Twitter response: {$twitter_error}."); } } } } if (!empty($media_id)) { $id = implode(',', $media_id); $params = array('status' => $status, 'media_ids' => "{$id}"); try { $response = $twitterAPI->request('POST', 'https://api.twitter.com/1.1/statuses/update.json', $params, true, false); \Idno\Core\Idno::site()->logging()->log("JSON from Twitter: " . var_export($twitterAPI->response['response'], true)); } catch (\Exception $e) { \Idno\Core\Idno::site()->logging()->log($e); } } /*$code = $twitterAPI->request( 'POST','https://upload.twitter.com/1.1/statuses/update_with_media', $params, true, // use auth true // multipart );*/ @unlink($filename); if (!empty($twitterAPI->response['response'])) { if ($json = json_decode($twitterAPI->response['response'])) { if (!empty($json->id_str)) { $object->setPosseLink('twitter', 'https://twitter.com/' . $json->user->screen_name . '/status/' . $json->id_str, '@' . $json->user->screen_name); $object->save(); } else { \Idno\Core\Idno::site()->logging()->log("Nothing was posted to Twitter: " . var_export($json, true)); } } else { \Idno\Core\Idno::site()->logging()->log("Bad JSON from Twitter: " . var_export($json, true)); } } } }); }