From 8de3469957b60d7938217611f9dd3afbdac1455d Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Thu, 31 Mar 2016 17:57:01 +0200 Subject: [PATCH 01/19] Constraint check Notice table, need to get foreign key array! --- classes/Notice.php | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/classes/Notice.php b/classes/Notice.php index b387b627bf..81c3df6336 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -3087,6 +3087,70 @@ class Notice extends Managed_DataObject $schema = Schema::get(); $schemadef = $schema->getTableDef($table); + printfnq("\nConstraint checking Notice table...\n"); + /** + * Improve typing and make sure no NULL values in any id-related columns are 0 + * 2016-03-31 + */ + foreach (['reply_to', 'repeat_of'] as $field) { + $notice = new Notice(); // reset the object + $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE %2$s=0', $notice->escapedTableName(), $field)); + // Now we're sure that no Notice entries have repeat_of=0, only an id > 0 or NULL + unset($notice); + } + + /** + * Make sure constraints are met before upgrading. + * 2016-03-31 + * + * Will find foreign keys which do not fulfill the constraints and fix + * where appropriate, such as delete when "repeat_of" ID not found in notice.id + * or set to NULL for "reply_to" in the same case. + * + * XXX: How does this work if we would use multicolumn foreign keys? + */ + foreach (['reply_to' => 'reset', 'repeat_of' => 'delete', 'profile' => 'delete'] as $field=>$action) { + $notice = new Notice(); + + $fkeyname = $notice->tableName().'_'.$field.'_fkey'; + assert(isset($schemadef['foreign keys'][$fkeyname]) && $schemadef['foreign keys'][$fkeyname]); + $foreign_key = $schemadef['foreign keys'][$fkeyname]; + printfnq("\n"._ve($schemadef)); + $fkeytable = $foreign_key[0]; + assert(isset($foreign_key[1][$field])); + $fkeycol = $foreign_key[1][$field]; + + // NOTE: Above we set all repeat_of to NULL if they were 0, so this really gets them all. + $notice->whereAdd(sprintf('%1$s NOT IN (SELECT %2$s FROM %3$s)', $field, $fkeycol, $fkeytable)); + if ($notice->find()) { + printfnq("\tFound {$notice->N} notices with {$field} NOT IN notice.id, {$action}ing..."); + switch ($action) { + case 'delete': // since it's a directly dependant notice for an unknown ID we don't want it in our DB + while ($notice->fetch()) { + // $notice->delete(); + printfnq("\n deleting {$notice->id}"); + } + break; + case 'reset': // just set it to NULL to be compatible with our constraints, if it was related to an unknown ID + $ids = []; + foreach ($notice->fetchAll('id') as $id) { + settype($id, 'int'); + $ids[] = $id; + } + $notice = new Notice(); + $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE id IN (%3$s)', + $notice->escapedTableName(), + $field, + implode(',', $ids))); + break; + default: + throw new ServerException('The programmer sucks, invalid action name when fixing table.'); + } + printfnq("DONE.\n"); + } + unset($notice); + } + // 2015-09-04 We move Notice location data to Notice_location // First we see if we have to do this at all if (!isset($schemadef['fields']['lat']) From 44ea8aa681132475f253960c694b8c001cdc5c0e Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Thu, 31 Mar 2016 20:51:50 +0200 Subject: [PATCH 02/19] Make sure $_SERVER['HTTP_REFERER'] isset when testing value --- lib/util.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index bc4898f847..b35eff84d8 100644 --- a/lib/util.php +++ b/lib/util.php @@ -266,7 +266,8 @@ function common_logged_in() function common_local_referer() { - return parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) === common_config('site', 'server'); + return isset($_SERVER['HTTP_REFERER']) + && parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) === common_config('site', 'server'); } function common_have_session() From 195285ac2f74d343979a0f7d520942e32d2df2cb Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 1 Apr 2016 06:24:11 +0200 Subject: [PATCH 03/19] Fix constraint checking and only run it if not already constrained --- classes/Notice.php | 125 ++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 81c3df6336..1b09c01a79 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -3087,68 +3087,77 @@ class Notice extends Managed_DataObject $schema = Schema::get(); $schemadef = $schema->getTableDef($table); - printfnq("\nConstraint checking Notice table...\n"); /** - * Improve typing and make sure no NULL values in any id-related columns are 0 + * Make sure constraints are met before upgrading, if foreign keys + * are not already in use. * 2016-03-31 */ - foreach (['reply_to', 'repeat_of'] as $field) { - $notice = new Notice(); // reset the object - $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE %2$s=0', $notice->escapedTableName(), $field)); - // Now we're sure that no Notice entries have repeat_of=0, only an id > 0 or NULL - unset($notice); - } - - /** - * Make sure constraints are met before upgrading. - * 2016-03-31 - * - * Will find foreign keys which do not fulfill the constraints and fix - * where appropriate, such as delete when "repeat_of" ID not found in notice.id - * or set to NULL for "reply_to" in the same case. - * - * XXX: How does this work if we would use multicolumn foreign keys? - */ - foreach (['reply_to' => 'reset', 'repeat_of' => 'delete', 'profile' => 'delete'] as $field=>$action) { - $notice = new Notice(); - - $fkeyname = $notice->tableName().'_'.$field.'_fkey'; - assert(isset($schemadef['foreign keys'][$fkeyname]) && $schemadef['foreign keys'][$fkeyname]); - $foreign_key = $schemadef['foreign keys'][$fkeyname]; - printfnq("\n"._ve($schemadef)); - $fkeytable = $foreign_key[0]; - assert(isset($foreign_key[1][$field])); - $fkeycol = $foreign_key[1][$field]; - - // NOTE: Above we set all repeat_of to NULL if they were 0, so this really gets them all. - $notice->whereAdd(sprintf('%1$s NOT IN (SELECT %2$s FROM %3$s)', $field, $fkeycol, $fkeytable)); - if ($notice->find()) { - printfnq("\tFound {$notice->N} notices with {$field} NOT IN notice.id, {$action}ing..."); - switch ($action) { - case 'delete': // since it's a directly dependant notice for an unknown ID we don't want it in our DB - while ($notice->fetch()) { - // $notice->delete(); - printfnq("\n deleting {$notice->id}"); - } - break; - case 'reset': // just set it to NULL to be compatible with our constraints, if it was related to an unknown ID - $ids = []; - foreach ($notice->fetchAll('id') as $id) { - settype($id, 'int'); - $ids[] = $id; - } - $notice = new Notice(); - $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE id IN (%3$s)', - $notice->escapedTableName(), - $field, - implode(',', $ids))); - break; - default: - throw new ServerException('The programmer sucks, invalid action name when fixing table.'); - } - printfnq("DONE.\n"); + if (!isset($schemadef['foreign keys'])) { + $newschemadef = self::schemaDef(); + printfnq("\nConstraint checking Notice table...\n"); + /** + * Improve typing and make sure no NULL values in any id-related columns are 0 + * 2016-03-31 + */ + foreach (['reply_to', 'repeat_of'] as $field) { + $notice = new Notice(); // reset the object + $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE %2$s=0', $notice->escapedTableName(), $field)); + // Now we're sure that no Notice entries have repeat_of=0, only an id > 0 or NULL + unset($notice); + } + + /** + * This Will find foreign keys which do not fulfill the constraints and fix + * where appropriate, such as delete when "repeat_of" ID not found in notice.id + * or set to NULL for "reply_to" in the same case. + * 2016-03-31 + * + * XXX: How does this work if we would use multicolumn foreign keys? + */ + foreach (['reply_to' => 'reset', 'repeat_of' => 'delete', 'profile_id' => 'delete'] as $field=>$action) { + $notice = new Notice(); + + $fkeyname = $notice->tableName().'_'.$field.'_fkey'; + assert(isset($newschemadef['foreign keys'][$fkeyname])); + assert($newschemadef['foreign keys'][$fkeyname]); + + $foreign_key = $newschemadef['foreign keys'][$fkeyname]; + $fkeytable = $foreign_key[0]; + assert(isset($foreign_key[1][$field])); + $fkeycol = $foreign_key[1][$field]; + + printfnq("* {$fkeyname} ({$field} => {$fkeytable}.{$fkeycol})\n"); + + // NOTE: Above we set all repeat_of to NULL if they were 0, so this really gets them all. + $notice->whereAdd(sprintf('%1$s NOT IN (SELECT %2$s FROM %3$s)', $field, $fkeycol, $fkeytable)); + if ($notice->find()) { + printfnq("\tFound {$notice->N} notices with {$field} NOT IN notice.id, {$action}ing..."); + switch ($action) { + case 'delete': // since it's a directly dependant notice for an unknown ID we don't want it in our DB + while ($notice->fetch()) { + $notice->delete(); + } + break; + case 'reset': // just set it to NULL to be compatible with our constraints, if it was related to an unknown ID + $ids = []; + foreach ($notice->fetchAll('id') as $id) { + settype($id, 'int'); + $ids[] = $id; + } + unset($notice); + $notice = new Notice(); + $notice->query(sprintf('UPDATE %1$s SET %2$s=NULL WHERE id IN (%3$s)', + $notice->escapedTableName(), + $field, + implode(',', $ids))); + break; + default: + throw new ServerException('The programmer sucks, invalid action name when fixing table.'); + } + printfnq("DONE.\n"); + } + unset($notice); } - unset($notice); } // 2015-09-04 We move Notice location data to Notice_location From 547f92de070f425b9b0415c7aa87b173c630a2b0 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 1 Apr 2016 06:51:19 +0200 Subject: [PATCH 04/19] Don't fail deleteRelated on NoProfileException --- lib/activityhandlerplugin.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/activityhandlerplugin.php b/lib/activityhandlerplugin.php index 8f28da85d6..c06f723a36 100644 --- a/lib/activityhandlerplugin.php +++ b/lib/activityhandlerplugin.php @@ -279,6 +279,10 @@ abstract class ActivityHandlerPlugin extends Plugin if ($this->isMyNotice($notice)) { try { $this->deleteRelated($notice); + } catch (NoProfileException $e) { + // we failed because of database lookup failure, Notice has no recognized profile as creator + // so we skip this. If we want to remove missing notices we should do a SQL constraints check + // in the affected plugin. } catch (AlreadyFulfilledException $e) { // Nothing to see here, it's obviously already gone... } From 922b65d2318bfedcac3fd076dae996187055470b Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 1 Apr 2016 23:10:34 +0200 Subject: [PATCH 05/19] More debugging in Salmon since we get situations which can't find inReplyToID --- plugins/OStatus/actions/usersalmon.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index ea5262aa3b..fd7b12317d 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -43,7 +43,9 @@ class UsersalmonAction extends SalmonAction if (!empty($this->activity->context->replyToID)) { try { $notice = Notice::getByUri($this->activity->context->replyToID); + common_debug('Referenced Notice object found with URI: '.$notice->getUri()); } catch (NoResultException $e) { + common_debug('Referenced Notice object NOT found with URI: '.$this->activity->context->replyToID); $notice = false; } } From b1de90fe0866fa30e72df6b2df6a937c39bebe28 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 1 Apr 2016 23:21:57 +0200 Subject: [PATCH 06/19] Send thr:in-reply-to as well, for clarity... --- plugins/Favorite/classes/Fave.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/Favorite/classes/Fave.php b/plugins/Favorite/classes/Fave.php index 7dad591181..c9bb7a6dd2 100644 --- a/plugins/Favorite/classes/Fave.php +++ b/plugins/Favorite/classes/Fave.php @@ -193,6 +193,13 @@ class Fave extends Managed_DataObject $act->content = sprintf(_('%1$s favorited something by %2$s: %3$s'), $actor->getNickname(), $target->getProfile()->getNickname(), $target->getRendered()); + $act->context = new ActivityContext(); + $act->context->replyToID = $target->getUri(); + try { + $act->context->replyToURL = $target->getUrl(); + } catch (InvalidUrlException $e) { + // ok, no replyToURL, i.e. the href="" in + } $act->actor = $actor->asActivityObject(); $act->target = $target->asActivityObject(); From 6d33c003fc8d8b09097549307305eb6e73f1d627 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 4 Apr 2016 12:04:20 +0200 Subject: [PATCH 07/19] Maybe stop deleteRelated from failing on constraint checking --- classes/Notice.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 1b09c01a79..6501a83adb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1537,12 +1537,16 @@ class Notice extends Managed_DataObject function getProfileTags() { - $profile = $this->getProfile(); - $list = $profile->getOtherTags($profile); $ptags = array(); + try { + $profile = $this->getProfile(); + $list = $profile->getOtherTags($profile); - while($list->fetch()) { - $ptags[] = clone($list); + while($list->fetch()) { + $ptags[] = clone($list); + } + } catch (Exception $e) { + common_log(LOG_ERR, "Error during Notice->getProfileTags() for id=={$this->getID()}: {$e->getMessage()}"); } return $ptags; From 4645033b98833f083767f3a8aabfcd44b97e9b14 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Fri, 8 Apr 2016 13:44:22 +0200 Subject: [PATCH 08/19] "In conversation" text in noticelistitem --- lib/noticelistitem.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/noticelistitem.php b/lib/noticelistitem.php index a0dcf6f30c..cbff03d973 100644 --- a/lib/noticelistitem.php +++ b/lib/noticelistitem.php @@ -189,6 +189,7 @@ class NoticeListItem extends Widget function showNoticeInfo() { if (Event::handle('StartShowNoticeInfo', array($this))) { + $this->showContextLink(); $this->showNoticeLink(); $this->showNoticeSource(); $this->showNoticeLocation(); @@ -375,14 +376,10 @@ class NoticeListItem extends Widget */ function showNoticeLink() { - $this->out->elementStart('a', array('rel' => 'bookmark', - 'class' => 'timestamp', - 'href' => Conversation::getUrlFromNotice($this->notice))); $this->out->element('time', array('class' => 'dt-published', 'datetime' => common_date_iso8601($this->notice->created), 'title' => common_exact_date($this->notice->created)), common_date_string($this->notice->created)); - $this->out->elementEnd('a'); } /** @@ -568,6 +565,18 @@ class NoticeListItem extends Widget } } + /** + * Show link to conversation view. + */ + function showContextLink() + { + $this->out->element('a', array('rel' => 'bookmark', + 'class' => 'timestamp', + 'href' => Conversation::getUrlFromNotice($this->notice)), + // TRANS: A link to the conversation view of a notice, on the local server. + _('In conversation')); + } + /** * show a link to reply to the current notice * From 107f612384a0a17897bc4b1cda3f521fc4e29324 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 18 Apr 2016 15:04:03 +0200 Subject: [PATCH 09/19] strict type comparison --- lib/imagefile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/imagefile.php b/lib/imagefile.php index a328df9852..85fc597126 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -93,7 +93,7 @@ class ImageFile $this->type = $info[2]; $this->mimetype = $info['mime']; - if ($this->type == IMAGETYPE_JPEG && function_exists('exif_read_data')) { + if ($this->type === IMAGETYPE_JPEG && function_exists('exif_read_data')) { // Orientation value to rotate thumbnails properly $exif = @exif_read_data($this->filepath); if (is_array($exif) && isset($exif['Orientation'])) { From c48508d5905ae3f26ddaa6e65f6e7da15b764ee1 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 18 Apr 2016 15:08:47 +0200 Subject: [PATCH 10/19] use getByID (also bad variable reference) --- classes/File_redirection.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 8a490fb18a..d1b266c90b 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -173,12 +173,11 @@ class File_redirection extends Managed_DataObject try { $r = File_redirection::getByUrl($in_url); - $f = File::getKV('id',$r->file_id); - - if($file instanceof File) { + try { + $f = File::getByID($r->file_id); $r->file = $f; - $r->redir_url = $f->url; - } else { + $r->redir_url = $f->url; + } catch (NoResultException $e) { // Invalid entry, delete and run again common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File redirection entry and and trying again..."); $r->delete(); From 5ccf3ed71497ffd02d8aac906e0a11d07e1cdefd Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 18 Apr 2016 15:21:05 +0200 Subject: [PATCH 11/19] function declaration to match parent --- actions/apihelptest.php | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/actions/apihelptest.php b/actions/apihelptest.php index a9cd7394c9..e57ebb710f 100644 --- a/actions/apihelptest.php +++ b/actions/apihelptest.php @@ -28,9 +28,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Returns the string "ok" in the requested format with a 200 OK HTTP status code. @@ -44,29 +42,9 @@ if (!defined('STATUSNET')) { */ class ApiHelpTestAction extends ApiPrivateAuthAction { - /** - * Take arguments for running - * - * @param array $args $_REQUEST args - * - * @return boolean success flag - */ - function prepare($args) + protected function handle() { - parent::prepare($args); - return true; - } - - /** - * Handle the request - * - * @param array $args $_REQUEST data (unused) - * - * @return void - */ - function handle($args) - { - parent::handle($args); + parent::handle(); if ($this->format == 'xml') { $this->initDocument('xml'); @@ -77,12 +55,8 @@ class ApiHelpTestAction extends ApiPrivateAuthAction print '"ok"'; $this->endDocument('json'); } else { - $this->clientError( - // TRANS: Client error displayed when coming across a non-supported API method. - _('API method not found.'), - 404, - $this->format - ); + // TRANS: Client error displayed when coming across a non-supported API method. + throw new ClientException(_('API method not found.'), 404); } } From ce65fe96ad5450ad748fc69c60611c0c5fb22154 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 18 Apr 2016 15:33:20 +0200 Subject: [PATCH 12/19] Oembed bugs with thumbnail generation. --- plugins/Oembed/actions/oembed.php | 39 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/plugins/Oembed/actions/oembed.php b/plugins/Oembed/actions/oembed.php index c374b8b34f..564e492e4a 100644 --- a/plugins/Oembed/actions/oembed.php +++ b/plugins/Oembed/actions/oembed.php @@ -84,26 +84,25 @@ class OembedAction extends Action $oembed['html']=$notice->getRendered(); // maybe add thumbnail - $attachments = $notice->attachments(); - if (!empty($attachments)) { - foreach ($attachments as $attachment) { - if(is_object($attachment)) { - try { - $thumb = $attachment->getThumbnail(); - } catch (ServerException $e) { - // - } - try { - $thumb_url = File_thumbnail::url($thumb->filename); - $oembed['thumbnail_url'] = $thumb_url; - break; // only first one - } catch (ClientException $e) { - // - } - } - } - } - + foreach ($notice->attachments() as $attachment) { + if (!$attachment instanceof File) { + common_debug('ATTACHMENTS array entry from notice id=='._ve($notice->getID()).' is something else than a File dataobject: '._ve($attachment)); + continue; + } + try { + $thumb = $attachment->getThumbnail(); + $thumb_url = File_thumbnail::url($thumb->filename); + $oembed['thumbnail_url'] = $thumb_url; + break; // only first one + } catch (UseFileAsThumbnailException $e) { + $oembed['thumbnail_url'] = $attachment->getUrl(); + break; // we're happy with that + } catch (ServerException $e) { + // + } catch (ClientException $e) { + // + } + } break; case 'attachment': From 0959efd7be98df62fda4ef9ec3fc1e8de42c8464 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 18 Apr 2016 15:56:52 +0200 Subject: [PATCH 13/19] Use constant for ATTN_PUBLIC (public collection) --- classes/Notice.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 6501a83adb..f38de37167 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -955,10 +955,10 @@ class Notice extends Managed_DataObject $act->context = new ActivityContext(); } - if (array_key_exists('http://activityschema.org/collection/public', $act->context->attention)) { + if (array_key_exists(ActivityContext::ATTN_PUBLIC, $act->context->attention)) { $stored->scope = Notice::PUBLIC_SCOPE; // TODO: maybe we should actually keep this? if the saveAttentions thing wants to use it... - unset($act->context->attention['http://activityschema.org/collection/public']); + unset($act->context->attention[ActivityContext::ATTN_PUBLIC]); } else { $stored->scope = self::figureOutScope($actor, $groups, $scope); } From 58274c99d48f29d05f0a29474dc922ef42a3648b Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 Apr 2016 01:50:40 +0200 Subject: [PATCH 14/19] Some PHP7 related package names --- INSTALL | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/INSTALL b/INSTALL index f7c2d21caf..ff755f2471 100644 --- a/INSTALL +++ b/INSTALL @@ -49,6 +49,19 @@ functional setup of GNU Social: - php5-mysqlnd The native driver for PHP5 MariaDB connections. If you use MySQL, 'php5-mysql' or 'php5-mysqli' may be enough. +Or, for PHP7, some or all of these will be necessary. PHP7 support is still +experimental and not necessarily working: + php7.0-bcmath + php7.0-curl + php7.0-exif + php7.0-gd + php7.0-intl + php7.0-mbstring + php7.0-mysqlnd + php7.0-opcache + php7.0-readline + php7.0-xmlwriter + The above package names are for Debian based systems. In the case of Arch Linux, PHP is compiled with support for most extensions but they require manual enabling in the relevant php.ini file (mostly php5-gmp). From af281606794358b05199f5b50fefd7fc4ec5b52a Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 Apr 2016 02:41:04 +0200 Subject: [PATCH 15/19] Naughty fix for extlib XMPPHP (PHP7) I shouldn't fix extlibs, but here goes anyway. I will see if there's an upstream library we can track which has fixed this themselves. --- plugins/Xmpp/extlib/XMPPHP/Roster.php | 4 ++-- plugins/Xmpp/extlib/XMPPHP/XMLStream.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/Xmpp/extlib/XMPPHP/Roster.php b/plugins/Xmpp/extlib/XMPPHP/Roster.php index 2e459e2a2f..69457b22a1 100644 --- a/plugins/Xmpp/extlib/XMPPHP/Roster.php +++ b/plugins/Xmpp/extlib/XMPPHP/Roster.php @@ -118,7 +118,7 @@ class Roster { * @param string $status */ public function setPresence($presence, $priority, $show, $status) { - list($jid, $resource) = split("/", $presence); + list($jid, $resource) = explode("/", $presence); if ($show != 'unavailable') { if (!$this->isContact($jid)) { $this->addContact($jid, 'not-in-roster'); @@ -137,7 +137,7 @@ class Roster { * @param string $jid */ public function getPresence($jid) { - $split = split("/", $jid); + $split = explode("/", $jid); $jid = $split[0]; if($this->isContact($jid)) { $current = array('resource' => '', 'active' => '', 'priority' => -129, 'show' => '', 'status' => ''); //Priorities can only be -128 = 127 diff --git a/plugins/Xmpp/extlib/XMPPHP/XMLStream.php b/plugins/Xmpp/extlib/XMPPHP/XMLStream.php index d33411ec54..5c71426200 100644 --- a/plugins/Xmpp/extlib/XMPPHP/XMLStream.php +++ b/plugins/Xmpp/extlib/XMPPHP/XMLStream.php @@ -263,7 +263,7 @@ class XMPPHP_XMLStream { $ns_tags = array($xpath); } foreach($ns_tags as $ns_tag) { - list($l, $r) = split("}", $ns_tag); + list($l, $r) = explode("}", $ns_tag); if ($r != null) { $xpart = array(substr($l, 1), $r); } else { @@ -564,7 +564,7 @@ class XMPPHP_XMLStream { if ($searchxml !== null) { if($handler[2] === null) $handler[2] = $this; $this->log->log("Calling {$handler[1]}", XMPPHP_Log::LEVEL_DEBUG); - $handler[2]->$handler[1]($this->xmlobj[2]); + $handler[2]->{$handler[1]}($this->xmlobj[2]); } } } @@ -578,13 +578,13 @@ class XMPPHP_XMLStream { if($searchxml !== null and $searchxml->name == $handler[0] and ($searchxml->ns == $handler[1] or (!$handler[1] and $searchxml->ns == $this->default_ns))) { if($handler[3] === null) $handler[3] = $this; $this->log->log("Calling {$handler[2]}", XMPPHP_Log::LEVEL_DEBUG); - $handler[3]->$handler[2]($this->xmlobj[2]); + $handler[3]->{$handler[2]}($this->xmlobj[2]); } } foreach($this->idhandlers as $id => $handler) { if(array_key_exists('id', $this->xmlobj[2]->attrs) and $this->xmlobj[2]->attrs['id'] == $id) { if($handler[1] === null) $handler[1] = $this; - $handler[1]->$handler[0]($this->xmlobj[2]); + $handler[1]->{$handler[0]}($this->xmlobj[2]); #id handlers are only used once unset($this->idhandlers[$id]); break; @@ -640,7 +640,7 @@ class XMPPHP_XMLStream { if($handler[2] === null) { $handler[2] = $this; } - $handler[2]->$handler[1]($payload); + $handler[2]->{$handler[1]}($payload); } } foreach($this->until as $key => $until) { From 3e9b0d6018dc5ce7328cd2b8281dafaef930ce10 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 Apr 2016 02:41:56 +0200 Subject: [PATCH 16/19] split is gone, use explode. PHP7 extlib fix --- plugins/DomainStatusNetwork/extlib/regDomain.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/DomainStatusNetwork/extlib/regDomain.inc.php b/plugins/DomainStatusNetwork/extlib/regDomain.inc.php index 389f6c4295..076c7b8714 100644 --- a/plugins/DomainStatusNetwork/extlib/regDomain.inc.php +++ b/plugins/DomainStatusNetwork/extlib/regDomain.inc.php @@ -37,7 +37,7 @@ function getRegisteredDomain($signingDomain) { global $tldTree; - $signingDomainParts = split('\.', $signingDomain); + $signingDomainParts = explode('.', $signingDomain); $result = findRegisteredDomain($signingDomainParts, $tldTree); @@ -80,4 +80,4 @@ function findRegisteredDomain($remainingSigningDomainParts, &$treeNode) { return NULL; } -?> \ No newline at end of file +?> From e4f688fcfdbe997dae4777d7280559c3e9f50dca Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Tue, 26 Apr 2016 02:57:14 +0200 Subject: [PATCH 17/19] naughty extlib fix (PHP7) The explode function didn't return empty elements (which split did) --- plugins/Xmpp/extlib/XMPPHP/Roster.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/Xmpp/extlib/XMPPHP/Roster.php b/plugins/Xmpp/extlib/XMPPHP/Roster.php index 69457b22a1..500ff6dcc1 100644 --- a/plugins/Xmpp/extlib/XMPPHP/Roster.php +++ b/plugins/Xmpp/extlib/XMPPHP/Roster.php @@ -118,12 +118,13 @@ class Roster { * @param string $status */ public function setPresence($presence, $priority, $show, $status) { - list($jid, $resource) = explode("/", $presence); + $parts = explode('/', $presence); + $jid = $parts[0]; + $resource = isset($parts[1]) ? $parts[1] : ''; // apparently we can do '' as an associative array index if ($show != 'unavailable') { if (!$this->isContact($jid)) { $this->addContact($jid, 'not-in-roster'); } - $resource = $resource ? $resource : ''; $this->roster_array[$jid]['presence'][$resource] = array('priority' => $priority, 'show' => $show, 'status' => $status); } else { //Nuke unavailable resources to save memory unset($this->roster_array[$jid]['resource'][$resource]); From 7aa9a69c2fcccc79ace8cdffa4765fec1ece5d77 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 1 May 2016 11:26:28 +0200 Subject: [PATCH 18/19] Link to attachment page instead of big-ass image --- classes/File.php | 5 +++++ lib/activityobject.php | 2 +- lib/attachmentlistitem.php | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/classes/File.php b/classes/File.php index 9643b78f18..46d4d5498d 100644 --- a/classes/File.php +++ b/classes/File.php @@ -516,6 +516,11 @@ class File extends Managed_DataObject return $filepath; } + public function getAttachmentUrl() + { + return common_local_url('attachment', array('attachment'=>$this->getID())); + } + public function getUrl($prefer_local=true) { if ($prefer_local && !empty($this->filename)) { diff --git a/lib/activityobject.php b/lib/activityobject.php index 87eea13727..ca6390b725 100644 --- a/lib/activityobject.php +++ b/lib/activityobject.php @@ -491,7 +491,7 @@ class ActivityObject $object->type = self::mimeTypeToObjectType($file->mimetype); $object->id = TagURI::mint(sprintf("file:%d", $file->id)); - $object->link = common_local_url('attachment', array('attachment' => $file->id)); + $object->link = $file->getAttachmentUrl(); if ($file->title) { $object->title = $file->title; diff --git a/lib/attachmentlistitem.php b/lib/attachmentlistitem.php index 6ee3c7087b..dc22c8af29 100644 --- a/lib/attachmentlistitem.php +++ b/lib/attachmentlistitem.php @@ -87,8 +87,8 @@ class AttachmentListItem extends Widget function linkAttr() { return array('class' => 'attachment', - 'href' => $this->attachment->getUrl(false), - 'id' => 'attachment-' . $this->attachment->id, + 'href' => $this->attachment->getAttachmentUrl(), + 'id' => 'attachment-' . $this->attachment->getID(), 'title' => $this->linkTitle()); } From 60130633f008b6d52ff426367122a3088cb4a84d Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 1 May 2016 11:36:07 +0200 Subject: [PATCH 19/19] Linkback references to unset indexes + spelling error --- plugins/Linkback/lib/util.php | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/plugins/Linkback/lib/util.php b/plugins/Linkback/lib/util.php index cd0476ceef..b0e99cbc94 100644 --- a/plugins/Linkback/lib/util.php +++ b/plugins/Linkback/lib/util.php @@ -201,13 +201,13 @@ function linkback_hcard($mf2, $url) { } function linkback_notice($source, $notice_or_user, $entry, $author, $mf2) { - $content = $entry['content'] ? $entry['content'][0]['html'] : - ($entry['summary'] ? $entry['sumary'][0] : $entry['name'][0]); + $content = isset($entry['content']) ? $entry['content'][0]['html'] : + (isset($entry['summary']) ? $entry['summary'][0] : $entry['name'][0]); $rendered = common_purify($content); if($notice_or_user instanceof Notice && $entry['type'] == 'mention') { - $name = $entry['name'] ? $entry['name'][0] : substr(common_strip_html($content), 0, 20).'…'; + $name = isset($entry['name']) ? $entry['name'][0] : substr(common_strip_html($content), 0, 20).'…'; $rendered = _m('linked to this from '.htmlspecialchars($name).''); } @@ -241,12 +241,16 @@ function linkback_notice($source, $notice_or_user, $entry, $author, $mf2) { } } - if($entry['published'] || $entry['updated']) { - $options['created'] = $entry['published'] ? common_sql_date($entry['published'][0]) : common_sql_date($entry['updated'][0]); + if (isset($entry['published']) || isset($entry['updated'])) { + $options['created'] = isset($entry['published']) + ? common_sql_date($entry['published'][0]) + : common_sql_date($entry['updated'][0]); } - if($entry['photo']) { + if (isset($entry['photo']) && common_valid_http_url($entry['photo'])) { $options['urls'][] = $entry['photo'][0]; + } elseif (isset($entry['photo'])) { + common_debug('Linkback got invalid HTTP URL for photo: '._ve($entry['photo'])); } foreach((array)$entry['category'] as $tag) { @@ -287,7 +291,7 @@ function linkback_profile($entry, $mf2, $response, $target) { $author = array('name' => $entry['name']); } - if(!$author['url']) { + if (!isset($author['url']) || empty($author['url'])) { $author['url'] = array($response->getEffectiveUrl()); } @@ -299,17 +303,16 @@ function linkback_profile($entry, $mf2, $response, $target) { try { $profile = Profile::fromUri($author['url'][0]); - } catch(UnknownUriException $ex) {} - - if(!($profile instanceof Profile)) { + } catch(UnknownUriException $ex) { $profile = Profile::getKV('profileurl', $author['url'][0]); } - if(!($profile instanceof Profile)) { + // XXX: Is this a good way to create the profile? + if (!$profile instanceof Profile) { $profile = new Profile(); $profile->profileurl = $author['url'][0]; $profile->fullname = $author['name'][0]; - $profile->nickname = $author['nickname'] ? $author['nickname'][0] : str_replace(' ', '', $author['name'][0]); + $profile->nickname = isset($author['nickname']) ? $author['nickname'][0] : str_replace(' ', '', $author['name'][0]); $profile->created = common_sql_now(); $profile->insert(); }