Exemplo n.º 1
0
 function getContent()
 {
     if (!empty($this->arguments[0])) {
         $object = \Idno\Entities\File::getByID($this->arguments[0]);
     }
     if (empty($object)) {
         $this->forward();
     }
     // TODO: 404
     $headers = apache_request_headers();
     if (isset($headers['If-Modified-Since'])) {
         if (strtotime($headers['If-Modified-Since']) < time() - 600) {
             header('HTTP/1.1 304 Not Modified');
             exit;
         }
     }
     header("Pragma: public");
     header('Expires: ' . date(\DateTime::RFC1123, time() + 86400 * 365));
     // Cache files for a year!
     if (!empty($object->file['mime_type'])) {
         header('Content-type: ' . $object->file['mime_type']);
     } else {
         header('Content-type: application/data');
     }
     echo $object->getBytes();
 }
Exemplo n.º 2
0
 function getContent()
 {
     // Check modified ts
     if ($cache = \Idno\Core\Idno::site()->cache()) {
         if ($modifiedts = $cache->load("{$this->arguments[0]}_modified_ts")) {
             $this->lastModifiedGatekeeper($modifiedts);
             // Set 304 and exit if we've not modified this object
         }
     }
     if (!empty($this->arguments[0])) {
         $object = \Idno\Entities\File::getByID($this->arguments[0]);
     }
     if (empty($object)) {
         $this->noContent();
     }
     session_write_close();
     // Close the session early
     //header("Pragma: public");
     // Determine uploaded timestamp
     if ($object instanceof \MongoGridFSFile) {
         $upload_ts = $object->file['uploadDate']->sec;
     } else {
         if (!empty($object->updated)) {
             $upload_ts = $object->updated;
         } else {
             if (!empty($object->created)) {
                 $upload_ts = $object->created;
             } else {
                 $upload_ts = time();
             }
         }
     }
     header("Pragma: public");
     header("Cache-Control: public");
     header('Expires: ' . date(\DateTime::RFC1123, time() + 86400 * 30));
     // Cache files for 30 days!
     $this->setLastModifiedHeader($upload_ts);
     if ($cache = \Idno\Core\Idno::site()->cache()) {
         $cache->store("{$this->arguments[0]}_modified_ts", $upload_ts);
     }
     if (!empty($object->file['mime_type'])) {
         header('Content-type: ' . $object->file['mime_type']);
     } else {
         header('Content-type: application/data');
     }
     //header('Accept-Ranges: bytes');
     //header('Content-Length: ' . filesize($object->getSize()));
     if (is_callable(array($object, 'passThroughBytes'))) {
         $object->passThroughBytes();
     } else {
         if ($stream = $object->getResource()) {
             while (!feof($stream)) {
                 echo fread($stream, 8192);
             }
         }
     }
 }
Exemplo n.º 3
0
 function getContent()
 {
     if (!empty($this->arguments[0])) {
         $object = \Idno\Entities\File::getByID($this->arguments[0]);
     }
     if (empty($object)) {
         $this->forward();
     }
     // TODO: 404
     session_write_close();
     // Close the session early
     //header("Pragma: public");
     // Determine uploaded timestamp
     if ($object instanceof \MongoGridFSFile) {
         $upload_ts = $object->file['uploadDate']->sec;
     } else {
         if (!empty($object->updated)) {
             $upload_ts = $object->updated;
         } else {
             if (!empty($object->created)) {
                 $upload_ts = $object->created;
             } else {
                 $upload_ts = time();
             }
         }
     }
     header("Pragma: public");
     header("Cache-Control: public");
     header('Expires: ' . date(\DateTime::RFC1123, time() + 86400 * 30));
     // Cache files for 30 days!
     $this->setLastModifiedHeader($upload_ts);
     if (!empty($object->file['mime_type'])) {
         header('Content-type: ' . $object->file['mime_type']);
     } else {
         header('Content-type: application/data');
     }
     //header('Accept-Ranges: bytes');
     //header('Content-Length: ' . filesize($object->getSize()));
     $headers = $this->getallheaders();
     if (isset($headers['If-Modified-Since'])) {
         if (strtotime($headers['If-Modified-Since']) <= $upload_ts) {
             //> time() - (86400 * 30)) {
             header('HTTP/1.1 304 Not Modified');
             exit;
         }
     }
     if (is_callable(array($object, 'passThroughBytes'))) {
         $object->passThroughBytes();
     } else {
         if ($stream = $object->getResource()) {
             while (!feof($stream)) {
                 echo fread($stream, 8192);
             }
         }
     }
 }
Exemplo n.º 4
0
 function postContent()
 {
     $this->adminGatekeeper();
     // Flag that a site export has been requested
     \Idno\Core\Idno::site()->config()->export_last_requested = time();
     \Idno\Core\Idno::site()->config()->export_in_progress = 1;
     \Idno\Core\Idno::site()->config()->save();
     $this->forward(\Idno\Core\Idno::site()->config()->getDisplayURL() . 'admin/export/', false);
     ignore_user_abort(true);
     // This is dangerous, but we need export to continue
     session_write_close();
     header('Connection: close');
     header('Content-length: ' . (string) ob_get_length());
     @ob_end_flush();
     // Return output to the browser
     @ob_end_clean();
     @flush();
     sleep(10);
     // Pause
     set_time_limit(0);
     // Eliminate time limit - this could take a while
     // Remove the previous export file
     if (!empty(\Idno\Core\Idno::site()->config()->export_file_id)) {
         if ($file = File::getByID(\Idno\Core\Idno::site()->config()->export_file_id)) {
             $file->remove();
             \Idno\Core\Idno::site()->config()->export_file_id = false;
             \Idno\Core\Idno::site()->config()->export_filename = false;
             \Idno\Core\Idno::site()->config()->save();
         }
     }
     if ($path = Migration::createCompressedArchive()) {
         $filename = \Idno\Core\Idno::site()->config()->host . '.zip';
         /*                    header('Content-disposition: attachment;filename=' . $filename);
                               if ($fp = fopen($path, 'r')) {
                                   while ($content = fread($fp, 4096)) {
                                       echo $content;
                                   }
                               }
                               fclose($fp);*/
         if ($file = File::createFromFile($path, $filename)) {
             @unlink($path);
             \Idno\Core\Idno::site()->config()->export_filename = $filename;
             \Idno\Core\Idno::site()->config()->export_file_id = $file;
             \Idno\Core\Idno::site()->config()->export_in_progress = 0;
             \Idno\Core\Idno::site()->config()->save();
             $mail = new Email();
             $mail->setHTMLBodyFromTemplate('admin/export');
             $mail->setTextBodyFromTemplate('admin/export');
             $mail->addTo(\Idno\Core\Idno::site()->session()->currentUser()->email);
             $mail->setSubject("Your data export is ready");
             $mail->send();
         }
         exit;
     }
 }
Exemplo n.º 5
0
 function postContent()
 {
     $this->adminGatekeeper();
     // Admins only
     if ($profile_user = $this->getInput('profile_user')) {
         \Idno\Core\Idno::site()->config->config['cherwell']['profile_user'] = $profile_user;
     }
     if (!empty($_FILES['background']) && $this->getInput('action') != 'clear') {
         if (in_array($_FILES['background']['type'], array('image/png', 'image/jpg', 'image/jpeg', 'image/gif'))) {
             if (getimagesize($_FILES['background']['tmp_name'])) {
                 if ($background = \Idno\Entities\File::createFromFile($_FILES['background']['tmp_name'], $_FILES['background']['name'])) {
                     // Remove previous bg
                     if (!empty(\Idno\Core\Idno::site()->config()->cherwell['bg_id'])) {
                         if ($file = File::getByID(\Idno\Core\Idno::site()->config()->cherwell['bg_id'])) {
                             if (is_callable([$file, 'delete'])) {
                                 // TODO: really need some abstraction here.
                                 $file->delete();
                             } else {
                                 if (is_callable([$file, 'remove'])) {
                                     $file->remove();
                                 }
                             }
                         }
                     }
                     \Idno\Core\Idno::site()->config->config['cherwell']['bg_id'] = $background;
                     $background = \Idno\Core\Idno::site()->config()->getDisplayURL() . 'file/' . $background;
                     \Idno\Core\Idno::site()->config->config['cherwell']['bg'] = $background;
                 }
             }
         }
     } else {
         // Remove previous bg
         if (!empty(\Idno\Core\Idno::site()->config()->cherwell['bg_id'])) {
             if ($file = File::getByID(\Idno\Core\Idno::site()->config()->cherwell['bg_id'])) {
                 if (is_callable([$file, 'delete'])) {
                     $file->delete();
                 } else {
                     if (is_callable([$file, 'remove'])) {
                         $file->remove();
                     }
                 }
             }
         }
         \Idno\Core\Idno::site()->config->cherwell = [];
     }
     \Idno\Core\Idno::site()->config->save();
     $this->forward(\Idno\Core\Idno::site()->config()->getDisplayURL() . 'admin/cherwell/');
 }
Exemplo n.º 6
0
 function getContent()
 {
     if (!empty($this->arguments[0])) {
         $object = \Idno\Entities\File::getByID($this->arguments[0]);
     }
     if (empty($object)) {
         $this->forward();
     }
     // TODO: 404
     if (!function_exists('getallheaders')) {
         function getallheaders()
         {
             $headers = '';
             foreach ($_SERVER as $name => $value) {
                 if (substr($name, 0, 5) == 'HTTP_') {
                     $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
                 }
             }
             return $headers;
         }
     }
     $headers = getallheaders();
     if (isset($headers['If-Modified-Since'])) {
         if (strtotime($headers['If-Modified-Since']) < time() - 600) {
             header('HTTP/1.1 304 Not Modified');
             exit;
         }
     }
     //header("Pragma: public");
     header('Expires: ' . date(\DateTime::RFC1123, time() + 86400 * 30));
     // Cache files for 30 days!
     if (!empty($object->file['mime_type'])) {
         header('Content-type: ' . $object->file['mime_type']);
     } else {
         header('Content-type: application/data');
     }
     //header('Accept-Ranges: bytes');
     //header('Content-Length: ' . filesize($object->getSize()));
     if (is_callable([$object, 'passThroughBytes'])) {
         $object->passThroughBytes();
     } else {
         echo $object->getBytes();
     }
 }
Exemplo n.º 7
0
 /**
  * Delete any files associated with this entity
  */
 function deleteAttachments()
 {
     if ($attachments = $this->getAttachments()) {
         foreach ($attachments as $attachment) {
             if ($file = \Idno\Entities\File::getByID($attachment['_id'])) {
                 $file->delete();
             }
         }
     }
 }
Exemplo n.º 8
0
 function getContent()
 {
     // Check modified ts
     if ($cache = \Idno\Core\Idno::site()->cache()) {
         if ($modifiedts = $cache->load("{$this->arguments[0]}_modified_ts")) {
             $this->lastModifiedGatekeeper($modifiedts);
             // Set 304 and exit if we've not modified this object
         }
     }
     if (!empty($this->arguments[0])) {
         $object = \Idno\Entities\File::getByID($this->arguments[0]);
     }
     if (empty($object)) {
         $this->noContent();
     }
     session_write_close();
     // Close the session early
     //header("Pragma: public");
     // Determine uploaded timestamp
     if ($object instanceof \MongoGridFSFile) {
         $upload_ts = $object->file['uploadDate']->sec;
     } else {
         if (!empty($object->updated)) {
             $upload_ts = $object->updated;
         } else {
             if (!empty($object->created)) {
                 $upload_ts = $object->created;
             } else {
                 $upload_ts = time();
             }
         }
     }
     header("Pragma: public");
     header("Cache-Control: public");
     header('Expires: ' . date(\DateTime::RFC1123, time() + 86400 * 30));
     // Cache files for 30 days!
     $this->setLastModifiedHeader($upload_ts);
     if ($cache = \Idno\Core\Idno::site()->cache()) {
         $cache->store("{$this->arguments[0]}_modified_ts", $upload_ts);
     }
     if (!empty($object->file['mime_type'])) {
         header('Content-type: ' . $object->file['mime_type']);
     } else {
         header('Content-type: application/data');
     }
     header('Accept-Ranges: bytes');
     // Partial content
     if (isset($_SERVER['HTTP_RANGE'])) {
         $size = $object->getSize();
         $start = 0;
         $end = $size - 1;
         $c_start = $start;
         $c_end = $end;
         // Parse range
         list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
         if ($range[0] == '-') {
             // Range form "-123"
             $c_start = (int) ($size - (int) substr($range, 1));
         } else {
             // Range form "123-" or "123-345"
             $range = explode('-', $range);
             $c_start = (int) $range[0];
             if (isset($range[1]) && is_numeric($range[1])) {
                 $c_end = (int) $range[1];
             }
         }
         \Idno\Core\Idno::site()->logging()->debug("Partial content request for {$c_start} - {$c_end} bytes from {$size} available bytes");
         // Validate range
         if ($c_start > $c_end || $c_end > $size || $c_start < 0) {
             $this->setResponse(416);
             header('HTTP/1.1 416 Requested Range Not Satisfiable');
             exit;
         }
         // Now output headers and partial content
         $this->setResponse(206);
         header('Content-Length: ' . ($c_end - $c_start));
         header("Content-Range: bytes {$c_start}-{$c_end}/{$size}");
         if ($stream = $object->getResource()) {
             fseek($stream, $c_start);
             echo fread($stream, $c_end - $c_start);
         }
     } else {
         header('Content-Length: ' . $object->getSize());
         if (is_callable(array($object, 'passThroughBytes'))) {
             $object->passThroughBytes();
         } else {
             if ($stream = $object->getResource()) {
                 while (!feof($stream)) {
                     echo fread($stream, 8192);
                 }
             }
         }
     }
 }
Exemplo n.º 9
0
 function registerEventHooks()
 {
     parent::registerEventHooks();
     Idno::site()->syndication()->registerService('indiesyndicate', function () {
         return true;
     }, ['note', 'article', 'image', 'like', 'share']);
     Idno::site()->addEventHook('user/auth/success', function (Event $event) {
         $is = (array) Idno::site()->session()->currentUser()->indiesyndicate;
         foreach ($is as $url => $details) {
             Idno::site()->syndication()->registerServiceAccount('indiesyndicate', $url, $details['name'], $details);
         }
     });
     Idno::site()->addEventHook('post/note/indiesyndicate', function (Event $event) {
         $eventdata = $event->data();
         $sa = $eventdata['syndication_account'];
         $object = $eventdata['object'];
         if ($this->doWebmention($sa, $object)) {
             return;
         }
         $details = $this->getAccountDetails($sa);
         $style = isset($details['style']) ? $details['style'] : 'default';
         $params = ['h' => 'entry', 'content' => $object->body, 'url' => $object->getSyndicationURL()];
         if (is_array($object->inreplyto) && !empty($object->inreplyto)) {
             $params['in-reply-to'] = $object->inreplyto[0];
         }
         $this->doMicropub($sa, $object, $params);
     });
     Idno::site()->addEventHook('post/image/indiesyndicate', function (Event $event) {
         $eventdata = $event->data();
         $sa = $eventdata['syndication_account'];
         $object = $eventdata['object'];
         if ($this->doWebmention($sa, $object)) {
             return;
         }
         $details = $this->getAccountDetails($sa);
         $style = isset($details['style']) ? $details['style'] : 'default';
         if ($style === 'microblog') {
             // combine name and content for twitter
             $content = '';
             if ($object->title) {
                 $content .= strip_tags($object->title);
             }
             if ($object->body) {
                 if (!empty($content)) {
                     $content .= "\n";
                 }
                 $content .= trim(strip_tags($object->body));
             }
             $params = ['h' => 'entry', 'content' => $content, 'url' => $object->getSyndicationURL()];
         } else {
             $params = ['h' => 'entry', 'name' => $object->title ? strip_tags($object->title) : '', 'content' => $object->body ? strip_tags($object->body) : '', 'url' => $object->getSyndicationURL()];
         }
         foreach ($object->getAttachments() as $attachment) {
             if ($file = \Idno\Entities\File::getByID($attachment['_id'])) {
                 $photofile = tempnam(sys_get_temp_dir(), 'indiesyndicate_photo');
                 $file->write($photofile);
                 $params['photo'] = '@' . $photofile;
                 break;
             }
         }
         $this->doMicropub($sa, $object, $params);
         if (isset($photofile)) {
             unlink($photofile);
         }
     });
     Idno::site()->addEventHook('post/article/indiesyndicate', function (Event $event) {
         $eventdata = $event->data();
         $sa = $eventdata['syndication_account'];
         $object = $eventdata['object'];
         if ($this->doWebmention($sa, $object)) {
             return;
         }
         $details = $this->getAccountDetails($sa);
         $style = isset($details['style']) ? $details['style'] : 'default';
         if ($style === 'microblog') {
             $params = ['h' => 'entry', 'content' => strip_tags($object->title) . ': ' . $object->getSyndicationURL(), 'url' => $object->getSyndicationURL()];
         } else {
             $params = ['h' => 'entry', 'name' => strip_tags($object->title), 'content' => strip_tags($object->body), 'url' => $object->getSyndicationURL()];
         }
         $this->doMicropub($sa, $object, $params);
     });
     Idno::site()->addEventHook('post/like/indiesyndicate', function (Event $event) {
         $eventdata = $event->data();
         $sa = $eventdata['syndication_account'];
         $object = $eventdata['object'];
         if ($this->doWebmention($sa, $object)) {
             return;
         }
         $details = $this->getAccountDetails($sa);
         $style = isset($details['style']) ? $details['style'] : 'default';
         $params = ['h' => 'entry', 'like-of' => $object->likeof, 'url' => $object->getSyndicationURL()];
         $this->doMicropub($sa, $object, $params);
     });
     Idno::site()->addEventHook('post/repost/indiesyndicate', function (Event $event) {
         $eventdata = $event->data();
         $sa = $eventdata['syndication_account'];
         $object = $eventdata['object'];
         if ($this->doWebmention($sa, $object)) {
             return;
         }
         $details = $this->getAccountDetails($sa);
         $style = isset($details['style']) ? $details['style'] : 'default';
         $params = ['h' => 'entry', 'repost-of' => $object->repostof, 'url' => $object->getSyndicationURL()];
         $this->doMicropub($sa, $object, $params);
     });
 }
Exemplo n.º 10
0
 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));
                 }
             }
         }
     });
 }