diff --git a/include/conversation.php b/include/conversation.php index c1d428f24..c10a7bec7 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -195,7 +195,7 @@ function localize_item(&$item) $xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">"; $obj = XML::parseString($xmlhead.$item['object']); - $links = XML::parseString($xmlhead."".unxmlify($obj->link).""); + $links = XML::parseString($xmlhead."".XML::unescape($obj->link).""); $Bname = $obj->title; $Blink = ""; diff --git a/include/text.php b/include/text.php index 7f66268ad..5da54b5fc 100644 --- a/include/text.php +++ b/include/text.php @@ -26,6 +26,7 @@ use Friendica\Util\Proxy as ProxyUtils; use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Model\FileTag; +use Friendica\Util\XML; require_once "include/conversation.php"; @@ -162,80 +163,6 @@ function autoname($len) { return $word; } - -/** - * escape text ($str) for XML transport - * @param string $str - * @return string Escaped text. - */ -function xmlify($str) { - /// @TODO deprecated code found? -/* $buffer = ''; - - $len = mb_strlen($str); - for ($x = 0; $x < $len; $x ++) { - $char = mb_substr($str,$x,1); - - switch($char) { - - case "\r" : - break; - case "&" : - $buffer .= '&'; - break; - case "'" : - $buffer .= '''; - break; - case "\"" : - $buffer .= '"'; - break; - case '<' : - $buffer .= '<'; - break; - case '>' : - $buffer .= '>'; - break; - case "\n" : - $buffer .= "\n"; - break; - default : - $buffer .= $char; - break; - } - }*/ - /* - $buffer = mb_ereg_replace("&", "&", $str); - $buffer = mb_ereg_replace("'", "'", $buffer); - $buffer = mb_ereg_replace('"', """, $buffer); - $buffer = mb_ereg_replace("<", "<", $buffer); - $buffer = mb_ereg_replace(">", ">", $buffer); - */ - $buffer = htmlspecialchars($str, ENT_QUOTES, "UTF-8"); - $buffer = trim($buffer); - - return $buffer; -} - - -/** - * undo an xmlify - * @param string $s xml escaped text - * @return string unescaped text - */ -function unxmlify($s) { - /// @TODO deprecated code found? -// $ret = str_replace('&','&', $s); -// $ret = str_replace(array('<','>','"','''),array('<','>','"',"'"),$ret); - /*$ret = mb_ereg_replace('&', '&', $s); - $ret = mb_ereg_replace(''', "'", $ret); - $ret = mb_ereg_replace('"', '"', $ret); - $ret = mb_ereg_replace('<', "<", $ret); - $ret = mb_ereg_replace('>', ">", $ret); - */ - $ret = htmlspecialchars_decode($s, ENT_QUOTES); - return $ret; -} - /** * Loader for infinite scrolling * @return string html for loader @@ -1047,9 +974,9 @@ function get_cats_and_terms($item) if ($cnt) { foreach ($matches as $mtch) { $categories[] = [ - 'name' => xmlify(FileTag::decode($mtch[1])), + 'name' => XML::escape(FileTag::decode($mtch[1])), 'url' => "#", - 'removeurl' => ((local_user() == $item['uid'])?'filerm/' . $item['id'] . '?f=&cat=' . xmlify(FileTag::decode($mtch[1])):""), + 'removeurl' => ((local_user() == $item['uid'])?'filerm/' . $item['id'] . '?f=&cat=' . XML::escape(FileTag::decode($mtch[1])):""), 'first' => $first, 'last' => false ]; @@ -1068,9 +995,9 @@ function get_cats_and_terms($item) if ($cnt) { foreach ($matches as $mtch) { $folders[] = [ - 'name' => xmlify(FileTag::decode($mtch[1])), + 'name' => XML::escape(FileTag::decode($mtch[1])), 'url' => "#", - 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . xmlify(FileTag::decode($mtch[1])) : ""), + 'removeurl' => ((local_user() == $item['uid']) ? 'filerm/' . $item['id'] . '?f=&term=' . XML::escape(FileTag::decode($mtch[1])) : ""), 'first' => $first, 'last' => false ]; @@ -1234,21 +1161,6 @@ function html2bb_video($s) { return $s; } -/** - * apply xmlify() to all values of array $val, recursively - * @param array $val - * @return array - */ -function array_xmlify($val){ - if (is_bool($val)) { - return $val?"true":"false"; - } elseif (is_array($val)) { - return array_map('array_xmlify', $val); - } - return xmlify((string) $val); -} - - /** * transform link href and img src from relative to absolute * diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 0403085f8..0f001b11a 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -256,7 +256,7 @@ function dfrn_confirm_post(App $a, $handsfree = null) $xml = XML::parseString($res); $status = (int) $xml->status; - $message = unxmlify($xml->message); // human readable text of what may have gone wrong. + $message = XML::unescape($xml->message); // human readable text of what may have gone wrong. switch ($status) { case 0: info(L10n::t("Confirmation completed successfully.") . EOL); diff --git a/mod/filer.php b/mod/filer.php index 11a5dd057..350807940 100644 --- a/mod/filer.php +++ b/mod/filer.php @@ -8,6 +8,7 @@ use Friendica\Core\Logger; use Friendica\Core\PConfig; use Friendica\Core\Renderer; use Friendica\Model\FileTag; +use Friendica\Util\XML; require_once 'include/items.php'; @@ -17,7 +18,7 @@ function filer_content(App $a) killme(); } - $term = unxmlify(trim(defaults($_GET, 'term', ''))); + $term = XML::unescape(trim(defaults($_GET, 'term', ''))); $item_id = (($a->argc > 1) ? intval($a->argv[1]) : 0); Logger::log('filer: tag ' . $term . ' item ' . $item_id); diff --git a/mod/filerm.php b/mod/filerm.php index d899d8f3f..335b27b32 100644 --- a/mod/filerm.php +++ b/mod/filerm.php @@ -4,6 +4,7 @@ use Friendica\App; use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\Model\FileTag; +use Friendica\Util\XML; function filerm_content(App $a) { @@ -12,8 +13,8 @@ function filerm_content(App $a) killme(); } - $term = unxmlify(trim($_GET['term'])); - $cat = unxmlify(trim($_GET['cat'])); + $term = XML::unescape(trim($_GET['term'])); + $cat = XML::unescape(trim($_GET['cat'])); $category = (($cat) ? true : false); diff --git a/mod/friendica.php b/mod/friendica.php index bf3f7942f..2629a0a19 100644 --- a/mod/friendica.php +++ b/mod/friendica.php @@ -46,18 +46,21 @@ function friendica_init(App $a) } $data = [ - 'version' => FRIENDICA_VERSION, - 'url' => System::baseUrl(), - 'addons' => $visible_addons, - 'locked_features' => $locked_features, - 'register_policy' => $register_policy[intval(Config::get('config', 'register_policy'))], - 'admin' => $admin, - 'site_name' => Config::get('config', 'sitename'), - 'platform' => FRIENDICA_PLATFORM, - 'info' => Config::get('config', 'info'), - 'no_scrape_url' => System::baseUrl().'/noscrape' + 'version' => FRIENDICA_VERSION, + 'url' => System::baseUrl(), + 'addons' => $visible_addons, + 'locked_features' => $locked_features, + 'explicit_content' => (int)Config::get('system', 'explicit_content', false), + 'language' => Config::get('system','language'), + 'register_policy ' => $register_policy[intval(Config::get('config', 'register_policy'))], + 'admin' => $admin, + 'site_name' => Config::get('config', 'sitename'), + 'platform' => FRIENDICA_PLATFORM, + 'info' => Config::get('config', 'info'), + 'no_scrape_url' => System::baseUrl().'/noscrape' ]; + header('Content-type: application/json; charset=utf-8'); echo json_encode($data); killme(); } diff --git a/mod/noscrape.php b/mod/noscrape.php index 3a8abe229..0964e85ca 100644 --- a/mod/noscrape.php +++ b/mod/noscrape.php @@ -27,12 +27,13 @@ function noscrape_init(App $a) Profile::load($a, $which, $profile); $json_info = [ - 'addr' => $a->profile['addr'], - 'nick' => $which, - 'guid' => $a->profile['guid'], - 'key' => $a->profile['pubkey'], - 'homepage' => System::baseUrl()."/profile/{$which}", - 'comm' => ($a->profile['account-type'] == Contact::ACCOUNT_TYPE_COMMUNITY), + 'addr' => $a->profile['addr'], + 'nick' => $which, + 'guid' => $a->profile['guid'], + 'key' => $a->profile['pubkey'], + 'homepage' => System::baseUrl()."/profile/{$which}", + 'comm' => ($a->profile['account-type'] == Contact::ACCOUNT_TYPE_COMMUNITY), + 'account-type' => $a->profile['account-type'], ]; if (!$a->profile['net-publish'] || $a->profile['hidewall']) { @@ -51,6 +52,7 @@ function noscrape_init(App $a) $json_info['fn'] = $a->profile['name']; $json_info['photo'] = $contactPhoto["photo"]; $json_info['tags'] = $keywords; + $json_info['language'] = $a->profile['language']; if (is_array($a->profile) && !$a->profile['hide-friends']) { /// @todo What should this value tell us? diff --git a/mod/photos.php b/mod/photos.php index 82a6ccca2..69b1972d4 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -30,6 +30,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; use Friendica\Util\Security; use Friendica\Util\Temporal; +use Friendica\Util\XML; require_once 'include/items.php'; @@ -682,15 +683,15 @@ function photos_post(App $a) $arr['body'] .= "\n\n" . '[url=' . System::baseUrl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . System::baseUrl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.' . $ext . '[/img][/url]' . "\n" ; $arr['object'] = '' . ACTIVITY_OBJ_PERSON . '' . $tagged[0] . '' . $tagged[1] . '/' . $tagged[0] . ''; - $arr['object'] .= '' . xmlify('' . "\n"); + $arr['object'] .= '' . XML::escape('' . "\n"); if ($tagged[3]) { - $arr['object'] .= xmlify('' . "\n"); + $arr['object'] .= XML::escape('' . "\n"); } $arr['object'] .= '' . "\n"; $arr['target'] = '' . ACTIVITY_OBJ_IMAGE . '' . $p[0]['desc'] . '' . System::baseUrl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ''; - $arr['target'] .= '' . xmlify('' . "\n" . '') . ''; + $arr['target'] .= '' . XML::escape('' . "\n" . '') . ''; $item_id = Item::insert($arr); } diff --git a/mod/poco.php b/mod/poco.php index 41fabff4e..08677ef8d 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -15,6 +15,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; +use Friendica\Util\XML; function poco_init(App $a) { $system_mode = false; @@ -375,7 +376,7 @@ function poco_init(App $a) { if ($format === 'xml') { header('Content-type: text/xml'); - echo Renderer::replaceMacros(Renderer::getMarkupTemplate('poco_xml.tpl'), array_xmlify(['$response' => $ret])); + echo Renderer::replaceMacros(Renderer::getMarkupTemplate('poco_xml.tpl'), XML::arrayEscape(['$response' => $ret])); killme(); } if ($format === 'json') { diff --git a/mod/poke.php b/mod/poke.php index be2625438..60ed5c402 100644 --- a/mod/poke.php +++ b/mod/poke.php @@ -22,6 +22,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; +use Friendica\Util\XML; require_once 'include/items.php'; @@ -124,9 +125,9 @@ function poke_init(App $a) $arr['body'] = '[url=' . $poster['url'] . ']' . $poster['name'] . '[/url]' . ' ' . L10n::t($verbs[$verb][0]) . ' ' . '[url=' . $target['url'] . ']' . $target['name'] . '[/url]'; $arr['object'] = '' . ACTIVITY_OBJ_PERSON . '' . $target['name'] . '' . $target['url'] . ''; - $arr['object'] .= '' . xmlify('' . "\n"); + $arr['object'] .= '' . XML::escape('' . "\n"); - $arr['object'] .= xmlify('' . "\n"); + $arr['object'] .= XML::escape('' . "\n"); $arr['object'] .= '' . "\n"; $item_id = Item::insert($arr); diff --git a/mod/profile.php b/mod/profile.php index f2df82849..cfbe07dad 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -24,6 +24,7 @@ use Friendica\Protocol\ActivityPub; use Friendica\Protocol\DFRN; use Friendica\Util\DateTimeFormat; use Friendica\Util\Security; +use Friendica\Util\XML; function profile_init(App $a) { @@ -209,7 +210,7 @@ function profile_content(App $a, $update = 0) $commvisitor = $commpage && $remote_contact; $a->page['aside'] .= posted_date_widget(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], $a->profile['profile_uid'], true); - $a->page['aside'] .= Widget::categories(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], (!empty($category) ? xmlify($category) : '')); + $a->page['aside'] .= Widget::categories(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], (!empty($category) ? XML::escape($category) : '')); $a->page['aside'] .= Widget::tagCloud(); if (Security::canWriteToUserWall($a->profile['profile_uid'])) { diff --git a/mod/subthread.php b/mod/subthread.php index 36cf835c2..425306b6f 100644 --- a/mod/subthread.php +++ b/mod/subthread.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Item; use Friendica\Util\Security; +use Friendica\Util\XML; require_once 'include/items.php'; @@ -87,7 +88,7 @@ function subthread_content(App $a) { $post_type = (($item['resource-id']) ? L10n::t('photo') : L10n::t('status')); $objtype = (($item['resource-id']) ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ); - $link = xmlify('' . "\n") ; + $link = XML::escape('' . "\n") ; $body = $item['body']; $obj = <<< EOT diff --git a/mod/tagger.php b/mod/tagger.php index edfcd7bd1..dd859e61c 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; +use Friendica\Util\XML; require_once 'include/items.php'; @@ -66,7 +67,7 @@ function tagger_content(App $a) { } $uri = Item::newURI($owner_uid); - $xterm = xmlify($term); + $xterm = XML::escape($term); $post_type = (($item['resource-id']) ? L10n::t('photo') : L10n::t('status')); $targettype = (($item['resource-id']) ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE ); @@ -76,9 +77,9 @@ function tagger_content(App $a) { $href = System::baseUrl() . '/display/' . $item['guid']; } - $link = xmlify('' . "\n") ; + $link = XML::escape('' . "\n") ; - $body = xmlify($item['body']); + $body = XML::escape($item['body']); $target = <<< EOT diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 2f78d0fd3..397a1863d 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -18,6 +18,7 @@ use Friendica\Model\Contact; use Friendica\Model\FileTag; use Friendica\Model\GContact; use Friendica\Model\Profile; +use Friendica\Util\XML; require_once 'boot.php'; require_once 'include/dba.php'; @@ -189,7 +190,7 @@ class Widget if ($cnt) { foreach ($matches as $mtch) { - $unescaped = xmlify(FileTag::decode($mtch[1])); + $unescaped = XML::escape(FileTag::decode($mtch[1])); $terms[] = array('name' => $unescaped, 'selected' => (($selected == $unescaped) ? 'selected' : '')); } } @@ -229,7 +230,7 @@ class Widget if ($cnt) { foreach ($matches as $mtch) { - $unescaped = xmlify(FileTag::decode($mtch[1])); + $unescaped = XML::escape(FileTag::decode($mtch[1])); $terms[] = array('name' => $unescaped, 'selected' => (($selected == $unescaped) ? 'selected' : '')); } } diff --git a/src/Model/Event.php b/src/Model/Event.php index ee61149de..f4df6ac9f 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -17,6 +17,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; +use Friendica\Util\XML; require_once 'boot.php'; require_once 'include/dba.php'; @@ -302,8 +303,8 @@ class Event extends BaseObject $item = Item::selectFirst(['id'], ['event-id' => $event['id'], 'uid' => $event['uid']]); if (DBA::isResult($item)) { - $object = '' . xmlify(ACTIVITY_OBJ_EVENT) . '' . xmlify($event['uri']) . ''; - $object .= '' . xmlify(self::getBBCode($event)) . ''; + $object = '' . XML::escape(ACTIVITY_OBJ_EVENT) . '' . XML::escape($event['uri']) . ''; + $object .= '' . XML::escape(self::getBBCode($event)) . ''; $object .= '' . "\n"; $fields = ['body' => self::getBBCode($event), 'object' => $object, 'edited' => $event['edited']]; @@ -353,8 +354,8 @@ class Event extends BaseObject $item_arr['body'] = self::getBBCode($event); $item_arr['event-id'] = $event['id']; - $item_arr['object'] = '' . xmlify(ACTIVITY_OBJ_EVENT) . '' . xmlify($event['uri']) . ''; - $item_arr['object'] .= '' . xmlify(self::getBBCode($event)) . ''; + $item_arr['object'] = '' . XML::escape(ACTIVITY_OBJ_EVENT) . '' . XML::escape($event['uri']) . ''; + $item_arr['object'] .= '' . XML::escape(self::getBBCode($event)) . ''; $item_arr['object'] .= '' . "\n"; $item_id = Item::insert($item_arr); diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 07a56cf24..33df28d92 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -2547,7 +2547,7 @@ class DFRN $item["guid"] = XML::getFirstNodeValue($xpath, "dfrn:diaspora_guid/text()", $entry); // We store the data from "dfrn:diaspora_signature" in a different table, this is done in "Item::insert" - $dsprsig = unxmlify(XML::getFirstNodeValue($xpath, "dfrn:diaspora_signature/text()", $entry)); + $dsprsig = XML::unescape(XML::getFirstNodeValue($xpath, "dfrn:diaspora_signature/text()", $entry)); if ($dsprsig != "") { $item["dsprsig"] = $dsprsig; } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 66a19d839..0b5c9c949 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -463,7 +463,7 @@ class Diaspora } return ['message' => (string)base64url_decode($base->data), - 'author' => unxmlify($author_addr), + 'author' => XML::unescape($author_addr), 'key' => (string)$key]; } @@ -603,7 +603,7 @@ class Diaspora Logger::log('Message verified.'); return ['message' => (string)$inner_decrypted, - 'author' => unxmlify($author_link), + 'author' => XML::unescape($author_link), 'key' => (string)$key]; } @@ -1505,9 +1505,9 @@ class Diaspora */ private static function receiveAccountMigration(array $importer, $data) { - $old_handle = notags(unxmlify($data->author)); - $new_handle = notags(unxmlify($data->profile->author)); - $signature = notags(unxmlify($data->signature)); + $old_handle = notags(XML::unescape($data->author)); + $new_handle = notags(XML::unescape($data->profile->author)); + $signature = notags(XML::unescape($data->signature)); $contact = self::contactByHandle($importer["uid"], $old_handle); if (!$contact) { @@ -1565,7 +1565,7 @@ class Diaspora */ private static function receiveAccountDeletion($data) { - $author = notags(unxmlify($data->author)); + $author = notags(XML::unescape($data->author)); $contacts = DBA::select('contact', ['id'], ['addr' => $author]); while ($contact = DBA::fetch($contacts)) { @@ -1656,19 +1656,19 @@ class Diaspora */ private static function receiveComment(array $importer, $sender, $data, $xml) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $parent_guid = notags(unxmlify($data->parent_guid)); - $text = unxmlify($data->text); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $parent_guid = notags(XML::unescape($data->parent_guid)); + $text = XML::unescape($data->text); if (isset($data->created_at)) { - $created_at = DateTimeFormat::utc(notags(unxmlify($data->created_at))); + $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); } else { $created_at = DateTimeFormat::utcNow(); } if (isset($data->thread_parent_guid)) { - $thread_parent_guid = notags(unxmlify($data->thread_parent_guid)); + $thread_parent_guid = notags(XML::unescape($data->thread_parent_guid)); $thr_uri = self::getUriFromGuid("", $thread_parent_guid, true); } else { $thr_uri = ""; @@ -1773,24 +1773,24 @@ class Diaspora */ private static function receiveConversationMessage(array $importer, array $contact, $data, $msg, $mesg, $conversation) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $subject = notags(unxmlify($data->subject)); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $subject = notags(XML::unescape($data->subject)); // "diaspora_handle" is the element name from the old version // "author" is the element name from the new version if ($mesg->author) { - $msg_author = notags(unxmlify($mesg->author)); + $msg_author = notags(XML::unescape($mesg->author)); } elseif ($mesg->diaspora_handle) { - $msg_author = notags(unxmlify($mesg->diaspora_handle)); + $msg_author = notags(XML::unescape($mesg->diaspora_handle)); } else { return false; } - $msg_guid = notags(unxmlify($mesg->guid)); - $msg_conversation_guid = notags(unxmlify($mesg->conversation_guid)); - $msg_text = unxmlify($mesg->text); - $msg_created_at = DateTimeFormat::utc(notags(unxmlify($mesg->created_at))); + $msg_guid = notags(XML::unescape($mesg->guid)); + $msg_conversation_guid = notags(XML::unescape($mesg->conversation_guid)); + $msg_text = XML::unescape($mesg->text); + $msg_created_at = DateTimeFormat::utc(notags(XML::unescape($mesg->created_at))); if ($msg_conversation_guid != $guid) { Logger::log("message conversation guid does not belong to the current conversation."); @@ -1861,11 +1861,11 @@ class Diaspora */ private static function receiveConversation(array $importer, $msg, $data) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $subject = notags(unxmlify($data->subject)); - $created_at = DateTimeFormat::utc(notags(unxmlify($data->created_at))); - $participants = notags(unxmlify($data->participants)); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $subject = notags(XML::unescape($data->subject)); + $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); + $participants = notags(XML::unescape($data->participants)); $messages = $data->message; @@ -1919,11 +1919,11 @@ class Diaspora */ private static function receiveLike(array $importer, $sender, $data) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $parent_guid = notags(unxmlify($data->parent_guid)); - $parent_type = notags(unxmlify($data->parent_type)); - $positive = notags(unxmlify($data->positive)); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $parent_guid = notags(XML::unescape($data->parent_guid)); + $parent_type = notags(XML::unescape($data->parent_type)); + $positive = notags(XML::unescape($data->positive)); // likes on comments aren't supported by Diaspora - only on posts // But maybe this will be supported in the future, so we will accept it. @@ -2028,11 +2028,11 @@ class Diaspora */ private static function receiveMessage(array $importer, $data) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $conversation_guid = notags(unxmlify($data->conversation_guid)); - $text = unxmlify($data->text); - $created_at = DateTimeFormat::utc(notags(unxmlify($data->created_at))); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $conversation_guid = notags(XML::unescape($data->conversation_guid)); + $text = XML::unescape($data->text); + $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); $contact = self::allowedContactByHandle($importer, $author, true); if (!$contact) { @@ -2103,8 +2103,8 @@ class Diaspora */ private static function receiveParticipation(array $importer, $data) { - $author = strtolower(notags(unxmlify($data->author))); - $parent_guid = notags(unxmlify($data->parent_guid)); + $author = strtolower(notags(XML::unescape($data->author))); + $parent_guid = notags(XML::unescape($data->parent_guid)); $contact_id = Contact::getIdForURL($author); if (!$contact_id) { @@ -2196,22 +2196,22 @@ class Diaspora */ private static function receiveProfile(array $importer, $data) { - $author = strtolower(notags(unxmlify($data->author))); + $author = strtolower(notags(XML::unescape($data->author))); $contact = self::contactByHandle($importer["uid"], $author); if (!$contact) { return false; } - $name = unxmlify($data->first_name).((strlen($data->last_name)) ? " ".unxmlify($data->last_name) : ""); - $image_url = unxmlify($data->image_url); - $birthday = unxmlify($data->birthday); - $gender = unxmlify($data->gender); - $about = Markdown::toBBCode(unxmlify($data->bio)); - $location = Markdown::toBBCode(unxmlify($data->location)); - $searchable = (unxmlify($data->searchable) == "true"); - $nsfw = (unxmlify($data->nsfw) == "true"); - $tags = unxmlify($data->tag_string); + $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? " ".XML::unescape($data->last_name) : ""); + $image_url = XML::unescape($data->image_url); + $birthday = XML::unescape($data->birthday); + $gender = XML::unescape($data->gender); + $about = Markdown::toBBCode(XML::unescape($data->bio)); + $location = Markdown::toBBCode(XML::unescape($data->location)); + $searchable = (XML::unescape($data->searchable) == "true"); + $nsfw = (XML::unescape($data->nsfw) == "true"); + $tags = XML::unescape($data->tag_string); $tags = explode("#", $tags); @@ -2310,8 +2310,8 @@ class Diaspora */ private static function receiveContactRequest(array $importer, $data) { - $author = unxmlify($data->author); - $recipient = unxmlify($data->recipient); + $author = XML::unescape($data->author); + $recipient = XML::unescape($data->recipient); if (!$author || !$recipient) { return false; @@ -2320,13 +2320,13 @@ class Diaspora // the current protocol version doesn't know these fields // That means that we will assume their existance if (isset($data->following)) { - $following = (unxmlify($data->following) == "true"); + $following = (XML::unescape($data->following) == "true"); } else { $following = true; } if (isset($data->sharing)) { - $sharing = (unxmlify($data->sharing) == "true"); + $sharing = (XML::unescape($data->sharing) == "true"); } else { $sharing = true; } @@ -2573,13 +2573,13 @@ class Diaspora */ private static function receiveReshare(array $importer, $data, $xml) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $created_at = DateTimeFormat::utc(notags(unxmlify($data->created_at))); - $root_author = notags(unxmlify($data->root_author)); - $root_guid = notags(unxmlify($data->root_guid)); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); + $root_author = notags(XML::unescape($data->root_author)); + $root_guid = notags(XML::unescape($data->root_guid)); /// @todo handle unprocessed property "provider_display_name" - $public = notags(unxmlify($data->public)); + $public = notags(XML::unescape($data->public)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2665,9 +2665,9 @@ class Diaspora */ private static function itemRetraction(array $importer, array $contact, $data) { - $author = notags(unxmlify($data->author)); - $target_guid = notags(unxmlify($data->target_guid)); - $target_type = notags(unxmlify($data->target_type)); + $author = notags(XML::unescape($data->author)); + $target_guid = notags(XML::unescape($data->target_guid)); + $target_type = notags(XML::unescape($data->target_type)); $person = self::personByHandle($author); if (!is_array($person)) { @@ -2729,7 +2729,7 @@ class Diaspora */ private static function receiveRetraction(array $importer, $sender, $data) { - $target_type = notags(unxmlify($data->target_type)); + $target_type = notags(XML::unescape($data->target_type)); $contact = self::contactByHandle($importer["uid"], $sender); if (!$contact && (in_array($target_type, ["Contact", "Person"]))) { @@ -2774,12 +2774,12 @@ class Diaspora */ private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, $xml) { - $author = notags(unxmlify($data->author)); - $guid = notags(unxmlify($data->guid)); - $created_at = DateTimeFormat::utc(notags(unxmlify($data->created_at))); - $public = notags(unxmlify($data->public)); - $text = unxmlify($data->text); - $provider_display_name = notags(unxmlify($data->provider_display_name)); + $author = notags(XML::unescape($data->author)); + $guid = notags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); + $public = notags(XML::unescape($data->public)); + $text = XML::unescape($data->text); + $provider_display_name = notags(XML::unescape($data->provider_display_name)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2794,7 +2794,7 @@ class Diaspora $address = []; if ($data->location) { foreach ($data->location->children() as $fieldname => $data) { - $address[$fieldname] = notags(unxmlify($data)); + $address[$fieldname] = notags(XML::unescape($data)); } } @@ -2805,8 +2805,8 @@ class Diaspora // Attach embedded pictures to the body if ($data->photo) { foreach ($data->photo as $photo) { - $body = "[img]".unxmlify($photo->remote_photo_path). - unxmlify($photo->remote_photo_name)."[/img]\n".$body; + $body = "[img]".XML::unescape($photo->remote_photo_path). + XML::unescape($photo->remote_photo_name)."[/img]\n".$body; } $datarray["object-type"] = ACTIVITY_OBJ_IMAGE; diff --git a/src/Util/XML.php b/src/Util/XML.php index 865c60406..c115e4d0d 100644 --- a/src/Util/XML.php +++ b/src/Util/XML.php @@ -36,7 +36,7 @@ class XML $root = new SimpleXMLElement("<".$key."/>"); self::fromArray($value, $root, $remove_header, $namespaces, false); } else { - $root = new SimpleXMLElement("<".$key.">".xmlify($value).""); + $root = new SimpleXMLElement("<".$key.">".self::escape($value).""); } $dom = dom_import_simplexml($root)->ownerDocument; @@ -104,7 +104,7 @@ class XML } if (!is_array($value)) { - $element = $xml->addChild($key, xmlify($value), $namespace); + $element = $xml->addChild($key, self::escape($value), $namespace); } elseif (is_array($value)) { $element = $xml->addChild($key, null, $namespace); self::fromArray($value, $element, $remove_header, $namespaces, false); @@ -123,7 +123,7 @@ class XML public static function copy(&$source, &$target, $elementname) { if (count($source->children()) == 0) { - $target->addChild($elementname, xmlify($source)); + $target->addChild($elementname, self::escape($source)); } else { $child = $target->addChild($elementname); foreach ($source->children() as $childfield => $childentry) { @@ -144,11 +144,11 @@ class XML */ public static function createElement($doc, $element, $value = "", $attributes = []) { - $element = $doc->createElement($element, xmlify($value)); + $element = $doc->createElement($element, self::escape($value)); foreach ($attributes as $key => $value) { $attribute = $doc->createAttribute($key); - $attribute->value = xmlify($value); + $attribute->value = self::escape($value); $element->appendChild($attribute); } return $element; @@ -462,4 +462,43 @@ class XML return $first_item->attributes; } + + /** + * escape text ($str) for XML transport + * @param string $str + * @return string Escaped text. + */ + public static function escape($str) + { + $buffer = htmlspecialchars($str, ENT_QUOTES, "UTF-8"); + $buffer = trim($buffer); + + return $buffer; + } + + /** + * undo an escape + * @param string $s xml escaped text + * @return string unescaped text + */ + public static function unescape($s) + { + $ret = htmlspecialchars_decode($s, ENT_QUOTES); + return $ret; + } + + /** + * apply escape() to all values of array $val, recursively + * @param array $val + * @return array + */ + public static function arrayEscape($val) + { + if (is_bool($val)) { + return $val?"true":"false"; + } elseif (is_array($val)) { + return array_map('XML::arrayEscape', $val); + } + return self::escape((string) $val); + } } diff --git a/tests/include/TextTest.php b/tests/include/TextTest.php index ac1b7d775..1422ee2ae 100644 --- a/tests/include/TextTest.php +++ b/tests/include/TextTest.php @@ -249,45 +249,6 @@ class TextTest extends TestCase ); } - /** - *xmlify and unxmlify - */ - public function testXmlify() - { - $text="I want to break\n this!11!"; - $xml=xmlify($text); - $retext=unxmlify($text); - - $this->assertEquals($text, $retext); - } - - /** - * xmlify and put in a document - */ - public function testXmlifyDocument() - { - $tag="I want to break"; - $xml=xmlify($tag); - $text=''.$xml.''; - - $xml_parser=xml_parser_create(); - //should be possible to parse it - $values=array(); - $index=array(); - $this->assertEquals(1, xml_parse_into_struct($xml_parser, $text, $values, $index)); - - $this->assertEquals( - array('TEXT'=>array(0)), - $index - ); - $this->assertEquals( - array(array('tag'=>'TEXT', 'type'=>'complete', 'level'=>1, 'value'=>$tag)), - $values - ); - - xml_parser_free($xml_parser); - } - /** * test hex2bin and reverse */ diff --git a/tests/src/Core/Cache/ArrayCacheDriverTest.php b/tests/src/Core/Cache/ArrayCacheDriverTest.php index 6863d149f..62c599d54 100644 --- a/tests/src/Core/Cache/ArrayCacheDriverTest.php +++ b/tests/src/Core/Cache/ArrayCacheDriverTest.php @@ -5,6 +5,10 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\ArrayCache; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class ArrayCacheDriverTest extends MemoryCacheTest { protected function getInstance() diff --git a/tests/src/Core/Cache/DatabaseCacheDriverTest.php b/tests/src/Core/Cache/DatabaseCacheDriverTest.php index 3cc4a72ed..60eb7b329 100644 --- a/tests/src/Core/Cache/DatabaseCacheDriverTest.php +++ b/tests/src/Core/Cache/DatabaseCacheDriverTest.php @@ -4,6 +4,10 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\CacheDriverFactory; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class DatabaseCacheDriverTest extends CacheTest { protected function getInstance() diff --git a/tests/src/Core/Cache/MemcacheCacheDriverTest.php b/tests/src/Core/Cache/MemcacheCacheDriverTest.php index db85723af..6a81cf46a 100644 --- a/tests/src/Core/Cache/MemcacheCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcacheCacheDriverTest.php @@ -3,7 +3,10 @@ namespace Friendica\Test\src\Core\Cache; - +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ use Friendica\Core\Cache\CacheDriverFactory; /** diff --git a/tests/src/Core/Cache/MemcachedCacheDriverTest.php b/tests/src/Core/Cache/MemcachedCacheDriverTest.php index fba5c4a95..d371f81fb 100644 --- a/tests/src/Core/Cache/MemcachedCacheDriverTest.php +++ b/tests/src/Core/Cache/MemcachedCacheDriverTest.php @@ -3,7 +3,10 @@ namespace Friendica\Test\src\Core\Cache; - +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ use Friendica\Core\Cache\CacheDriverFactory; /** diff --git a/tests/src/Core/Cache/RedisCacheDriverTest.php b/tests/src/Core/Cache/RedisCacheDriverTest.php index 0ee73945b..17079f1e0 100644 --- a/tests/src/Core/Cache/RedisCacheDriverTest.php +++ b/tests/src/Core/Cache/RedisCacheDriverTest.php @@ -3,7 +3,10 @@ namespace Friendica\Test\src\Core\Cache; - +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ use Friendica\Core\Cache\CacheDriverFactory; /** diff --git a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php index 671341718..bfea27253 100644 --- a/tests/src/Core/Lock/ArrayCacheLockDriverTest.php +++ b/tests/src/Core/Lock/ArrayCacheLockDriverTest.php @@ -6,6 +6,10 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\Core\Cache\ArrayCache; use Friendica\Core\Lock\CacheLockDriver; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class ArrayCacheLockDriverTest extends LockTest { protected function getInstance() diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php index 270d20079..e5ca825c9 100644 --- a/tests/src/Core/Lock/DatabaseLockDriverTest.php +++ b/tests/src/Core/Lock/DatabaseLockDriverTest.php @@ -5,6 +5,10 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\Core\Lock\DatabaseLockDriver; use Friendica\Database\DBA; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class DatabaseLockDriverTest extends LockTest { protected function getInstance() diff --git a/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php b/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php index ca9b9b463..c46eb6faa 100644 --- a/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php +++ b/tests/src/Core/Lock/MemcacheCacheLockDriverTest.php @@ -8,6 +8,8 @@ use Friendica\Core\Lock\CacheLockDriver; /** * @requires extension Memcache + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class MemcacheCacheLockDriverTest extends LockTest { diff --git a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php index 71311d5ba..4a508919a 100644 --- a/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php +++ b/tests/src/Core/Lock/MemcachedCacheLockDriverTest.php @@ -8,6 +8,8 @@ use Friendica\Core\Lock\CacheLockDriver; /** * @requires extension memcached + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class MemcachedCacheLockDriverTest extends LockTest { diff --git a/tests/src/Core/Lock/RedisCacheLockDriverTest.php b/tests/src/Core/Lock/RedisCacheLockDriverTest.php index 43cedb9cb..e537e50c1 100644 --- a/tests/src/Core/Lock/RedisCacheLockDriverTest.php +++ b/tests/src/Core/Lock/RedisCacheLockDriverTest.php @@ -8,6 +8,8 @@ use Friendica\Core\Lock\CacheLockDriver; /** * @requires extension redis + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled */ class RedisCacheLockDriverTest extends LockTest { diff --git a/tests/src/Core/Lock/SemaphoreLockDriverTest.php b/tests/src/Core/Lock/SemaphoreLockDriverTest.php index 39f0763fb..422ab3221 100644 --- a/tests/src/Core/Lock/SemaphoreLockDriverTest.php +++ b/tests/src/Core/Lock/SemaphoreLockDriverTest.php @@ -4,6 +4,10 @@ namespace Friendica\Test\src\Core\Lock; use Friendica\Core\Lock\SemaphoreLockDriver; +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ class SemaphoreLockDriverTest extends LockTest { protected function getInstance() diff --git a/tests/src/Util/XmlTest.php b/tests/src/Util/XmlTest.php new file mode 100644 index 000000000..ba78e4ff1 --- /dev/null +++ b/tests/src/Util/XmlTest.php @@ -0,0 +1,49 @@ +I want to break\n this!11!"; + $xml=XML::escape($text); + $retext=XML::unescape($text); + $this->assertEquals($text, $retext); + } + + /** + * escape and put in a document + */ + public function testEscapeDocument() + { + $tag="I want to break"; + $xml=XML::escape($tag); + $text=''.$xml.''; + $xml_parser=xml_parser_create(); + //should be possible to parse it + $values=array(); + $index=array(); + $this->assertEquals(1, xml_parse_into_struct($xml_parser, $text, $values, $index)); + $this->assertEquals( + array('TEXT'=>array(0)), + $index + ); + $this->assertEquals( + array(array('tag'=>'TEXT', 'type'=>'complete', 'level'=>1, 'value'=>$tag)), + $values + ); + xml_parser_free($xml_parser); + } +}