X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Futil.php;h=62289ebe329d4d88bda89b1bdc07cd232d845ceb;hb=d6b28c64830f632bb2f4b6f3c9369b9e56ad217a;hp=22962325778f3f09ab28575007f637f995d91b01;hpb=035aae2745e25d44ab9fe1b7bdffbcaa505ba970;p=quix0rs-gnu-social.git diff --git a/lib/util.php b/lib/util.php index 2296232577..62289ebe32 100644 --- a/lib/util.php +++ b/lib/util.php @@ -210,7 +210,7 @@ function common_language() /** * Salted, hashed passwords are stored in the DB. */ -function common_munge_password($password, $id, Profile $profile=null) +function common_munge_password($password, Profile $profile=null) { $hashed = null; @@ -245,8 +245,7 @@ function common_check_user($nickname, $password) } if ($user instanceof User && !empty($password)) { - if (0 == strcmp(common_munge_password($password, $user->id), - $user->password)) { + if (0 == strcmp(common_munge_password($password, $user->getProfile()), $user->password)) { //internal checking passed $authenticatedUser = $user; } @@ -576,18 +575,47 @@ function common_canonical_email($email) return $email; } +function common_purify($html) +{ + require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php'; + + $config = array('safe' => 1, // means that elements=* means elements=*-applet-embed-iframe-object-script or so + 'elements' => '*', + 'deny_attribute' => 'id,style,on*'); + + // Remove more elements than what the 'safe' filter gives (elements must be '*' before this) + // http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s3.6 + foreach (common_config('htmlfilter') as $tag=>$filter) { + if ($filter === true) { + $config['elements'] .= "-{$tag}"; + } + } + + $html = common_remove_unicode_formatting($html); + + return htmLawed($html, $config); +} + +function common_remove_unicode_formatting($text) +{ + // Strip Unicode text formatting/direction codes + // this is pretty dangerous for visualisation of text and can be used for mischief + return preg_replace('/[\\x{200b}-\\x{200f}\\x{202a}-\\x{202e}]/u', '', $text); +} + /** * Partial notice markup rendering step: build links to !group references. * - * @param string $text partially rendered HTML - * @param Notice $notice in whose context we're working + * @param string $text partially rendered HTML + * @param Profile $author the Profile that is composing the current notice + * @param Notice $parent the Notice this is sent in reply to, if any * @return string partially rendered HTML */ -function common_render_content($text, Notice $notice) +function common_render_content($text, Profile $author, Notice $parent=null) { - $r = common_render_text($text); - $r = common_linkify_mentions($r, $notice); - return $r; + $text = common_render_text($text); + $text = common_linkify_mentions($text, $author, $parent); + return $text; } /** @@ -596,13 +624,14 @@ function common_render_content($text, Notice $notice) * * Should generally not be called except from common_render_content(). * - * @param string $text partially-rendered HTML - * @param Notice $notice in-progress or complete Notice object for context + * @param string $text partially-rendered HTML + * @param Profile $author the Profile that is composing the current notice + * @param Notice $parent the Notice this is sent in reply to, if any * @return string partially-rendered HTML */ -function common_linkify_mentions($text, $notice) +function common_linkify_mentions($text, Profile $author, Notice $parent=null) { - $mentions = common_find_mentions($text, $notice); + $mentions = common_find_mentions($text, $author, $parent); // We need to go through in reverse order by position, // so our positions stay valid despite our fudging with the @@ -621,13 +650,13 @@ function common_linkify_mentions($text, $notice) $linkText = common_linkify_mention($mention); - $text = substr_replace($text, $linkText, $position, mb_strlen($mention['text'])); + $text = substr_replace($text, $linkText, $position, $mention['length']); } return $text; } -function common_linkify_mention($mention) +function common_linkify_mention(array $mention) { $output = null; @@ -660,50 +689,33 @@ function common_linkify_mention($mention) * Note the return data format is internal, to be used for building links and * such. Should not be used directly; rather, call common_linkify_mentions(). * - * @param string $text - * @param Notice $notice notice in whose context we're building links + * @param string $text + * @param Profile $sender the Profile that is sending the current text + * @param Notice $parent the Notice this text is in reply to, if any * * @return array * * @access private */ -function common_find_mentions($text, Notice $notice) +function common_find_mentions($text, Profile $sender, Notice $parent=null) { - try { - $sender = Profile::getKV('id', $notice->profile_id); - } catch (NoProfileException $e) { - return array(); - } - $mentions = array(); if (Event::handle('StartFindMentions', array($sender, $text, &$mentions))) { // Get the context of the original notice, if any - $origAuthor = null; - $origNotice = null; $origMentions = array(); - // Is it a reply? - - if ($notice instanceof Notice) { - try { - $origNotice = $notice->getParent(); - $origAuthor = $origNotice->getProfile(); - - $ids = $origNotice->getReplies(); + // Does it have a parent notice for context? + if ($parent instanceof Notice) { + $ids = $parent->getReplies(); // replied-to _profile ids_ - foreach ($ids as $id) { - $repliedTo = Profile::getKV('id', $id); - if ($repliedTo instanceof Profile) { - $origMentions[$repliedTo->nickname] = $repliedTo; - } + foreach ($ids as $id) { + try { + $repliedTo = Profile::getByID($id); + $origMentions[$repliedTo->getNickname()] = $repliedTo; + } catch (NoResultException $e) { + // continue foreach } - } catch (NoProfileException $e) { - common_log(LOG_WARNING, sprintf('Notice %d author profile id %d does not exist', $origNotice->id, $origNotice->profile_id)); - } catch (ServerException $e) { - // Probably just no parent. Should get a specific NoParentException - } catch (Exception $e) { - common_log(LOG_WARNING, __METHOD__ . ' got exception ' . get_class($e) . ' : ' . $e->getMessage()); } } @@ -721,34 +733,33 @@ function common_find_mentions($text, Notice $notice) // Start with conversation context, then go to // sender context. - if ($origAuthor instanceof Profile && $origAuthor->nickname == $nickname) { - $mentioned = $origAuthor; + if ($parent instanceof Notice && $parent->getProfile()->getNickname() === $nickname) { + $mentioned = $parent->getProfile(); } else if (!empty($origMentions) && array_key_exists($nickname, $origMentions)) { $mentioned = $origMentions[$nickname]; } else { + // sets to null if no match $mentioned = common_relative_profile($sender, $nickname); } if ($mentioned instanceof Profile) { $user = User::getKV('id', $mentioned->id); - if ($user instanceof User) { - $url = common_local_url('userbyid', array('id' => $user->id)); - } else { - $url = $mentioned->profileurl; + try { + $url = $mentioned->getUrl(); + } catch (InvalidUrlException $e) { + $url = common_local_url('userbyid', array('id' => $mentioned->getID())); } $mention = array('mentioned' => array($mentioned), 'type' => 'mention', 'text' => $match[0], 'position' => $match[1], + 'length' => mb_strlen($match[0]), + 'title' => $mentioned->getFullname(), 'url' => $url); - if (!empty($mentioned->fullname)) { - $mention['title'] = $mentioned->fullname; - } - $mentions[] = $mention; } } @@ -759,20 +770,21 @@ function common_find_mentions($text, Notice $notice) $text, $hmatches, PREG_OFFSET_CAPTURE); foreach ($hmatches[1] as $hmatch) { $tag = common_canonical_tag($hmatch[0]); - $plist = Profile_list::getByTaggerAndTag($sender->id, $tag); + $plist = Profile_list::getByTaggerAndTag($sender->getID(), $tag); if (!$plist instanceof Profile_list || $plist->private) { continue; } $tagged = $sender->getTaggedSubscribers($tag); $url = common_local_url('showprofiletag', - array('tagger' => $sender->nickname, + array('nickname' => $sender->getNickname(), 'tag' => $tag)); $mentions[] = array('mentioned' => $tagged, 'type' => 'list', 'text' => $hmatch[0], 'position' => $hmatch[1], + 'length' => mb_strlen($hmatch[0]), 'url' => $url); } @@ -792,6 +804,7 @@ function common_find_mentions($text, Notice $notice) 'type' => 'group', 'text' => $hmatch[0], 'position' => $hmatch[1], + 'length' => mb_strlen($hmatch[0]), 'url' => $group->permalink(), 'title' => $group->getFancyName()); } @@ -829,14 +842,15 @@ function common_find_mentions_raw($text) function common_render_text($text) { - $r = nl2br(htmlspecialchars($text)); + $text = common_remove_unicode_formatting($text); + $text = nl2br(htmlspecialchars($text)); - $r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r); - $r = common_replace_urls_callback($r, 'common_linkify'); - $r = preg_replace_callback('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u', - function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $r); + $text = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $text); + $text = common_replace_urls_callback($text, 'common_linkify'); + $text = preg_replace_callback('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u', + function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $text); // XXX: machine tags - return $r; + return $text; } /** @@ -854,7 +868,7 @@ function common_replace_urls_callback($text, $callback, $arg = null) { '(?:'. '(?:'. //Known protocols '(?:'. - '(?:(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://)'. + '(?:(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|ircs?)://)'. '|'. '(?:(?:mailto|aim|tel|xmpp):)'. ')'. @@ -867,15 +881,19 @@ function common_replace_urls_callback($text, $callback, $arg = null) { ')'. ')'. ')'. + '|(?:(?:magnet):)'. // URLs without domain name '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4 '|(?:'. //IPv6 '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?url; } $attrs = array('href' => $canon, 'title' => $longurl); @@ -1116,6 +1123,27 @@ function common_xml_safe_str($str) return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str); } +function common_slugify($str) +{ + // php5-intl is highly recommended... + if (!function_exists('transliterator_transliterate')) { + $str = preg_replace('/[^\pL\pN]/u', '', $str); + $str = mb_convert_case($str, MB_CASE_LOWER, 'UTF-8'); + $str = substr($str, 0, 64); + return $str; + } + $str = transliterator_transliterate( + 'Any-Latin;' . // any charset to latin compatible + 'NFD;' . // decompose + '[:Nonspacing Mark:] Remove;' . // remove nonspacing marks (accents etc.) + 'NFC;' . // composite again + '[:Punctuation:] Remove;' . // remove punctuation (.,¿? etc.) + 'Lower();' . // turn into lowercase + 'Latin-ASCII;', // get ASCII equivalents (ð to d for example) + $str); + return preg_replace('/[^\pL\pN]/', '', $str); +} + function common_tag_link($tag) { $canonical = common_canonical_tag($tag); @@ -1139,11 +1167,9 @@ function common_tag_link($tag) function common_canonical_tag($tag) { - // only alphanum - $tag = preg_replace('/[^\pL\pN]/u', '', $tag); - $tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8"); - $tag = substr($tag, 0, 64); - return $tag; + $tag = common_slugify($tag); + $tag = substr($tag, 0, 64); + return $tag; } function common_valid_profile_tag($str) @@ -1218,7 +1244,7 @@ function common_local_url($action, $args=null, $params=null, $fragment=null, $ad $path = $r->build($action, $args, $params, $fragment); $ssl = common_config('site', 'ssl') === 'always' - || StatusNet::isHTTPS() + || GNUsocial::isHTTPS() || common_is_sensitive($action); if (common_config('site','fancy')) { @@ -1259,10 +1285,10 @@ function common_is_sensitive($action) function common_path($relative, $ssl=false, $addSession=true) { - $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : ''; + $pathpart = (!empty(common_config('site', 'path'))) ? common_config('site', 'path') . '/' : ''; if (($ssl && (common_config('site', 'ssl') === 'sometimes')) - || StatusNet::isHTTPS() + || GNUsocial::isHTTPS() || common_config('site', 'ssl') === 'always') { $proto = 'https'; if (is_string(common_config('site', 'sslserver')) && @@ -1511,14 +1537,24 @@ function common_root_url($ssl=false) } /** - * returns $bytes bytes of random data as a hexadecimal string + * returns $bytes bytes of raw random data */ -function common_random_hexstr($bytes) +function common_random_rawstr($bytes) { - $str = @file_exists('/dev/urandom') + $rawstr = @file_exists('/dev/urandom') ? common_urandom($bytes) : common_mtrand($bytes); + return $rawstr; +} + +/** + * returns $bytes bytes of random data as a hexadecimal string + */ +function common_random_hexstr($bytes) +{ + $str = common_random_rawstr($bytes); + $hexstr = ''; for ($i = 0; $i < $bytes; $i++) { $hexstr .= sprintf("%02x", ord($str[$i])); @@ -1822,6 +1858,7 @@ function common_get_mime_media($type) return strtolower($tmp[0]); } +// Get only the mimetype and not additional info (separated from bare mime with semi-colon) function common_bare_mime($mimetype) { $mimetype = mb_strtolower($mimetype); @@ -1887,9 +1924,14 @@ function common_negotiate_type($cprefs, $sprefs) return $besttype; } -function common_config($main, $sub) +function common_config($main, $sub=null) { global $config; + if (is_null($sub)) { + // Return the config category array + return array_key_exists($main, $config) ? $config[$main] : array(); + } + // Return the config value return (array_key_exists($main, $config) && array_key_exists($sub, $config[$main])) ? $config[$main][$sub] : false; } @@ -2380,3 +2422,12 @@ function common_strip_html($html, $trim=true, $save_whitespace=false) $text = html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8'); return $trim ? trim($text) : $text; } + +function html_sprintf() +{ + $args = func_get_args(); + for ($i=1; $i