diff --git a/.travis.yml b/.travis.yml index 82b5a5d218..78c29817db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,11 +10,10 @@ php: services: - mysql env: - - USER=travis DB=test + - MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USERNAME=travis MYSQL_PASSWORD= MYSQL_DATABASE=test install: - composer install before_script: - mysql -e 'CREATE DATABASE IF NOT EXISTS test;' - # In order to avoid bin/worker.php warnings - - touch .htconfig.php + - mysql -utravis test < database.sql diff --git a/boot.php b/boot.php index 249fd9a891..b58e1bbc0d 100644 --- a/boot.php +++ b/boot.php @@ -499,36 +499,6 @@ if (!defined("SIGTERM")) { if (!defined('CURLE_OPERATION_TIMEDOUT')) { define('CURLE_OPERATION_TIMEDOUT', CURLE_OPERATION_TIMEOUTED); } -/** - * Reverse the effect of magic_quotes_gpc if it is enabled. - * Please disable magic_quotes_gpc so we don't have to do this. - * See http://php.net/manual/en/security.magicquotes.disabling.php - */ -function startup() -{ - error_reporting(E_ERROR | E_WARNING | E_PARSE); - - set_time_limit(0); - - // This has to be quite large to deal with embedded private photos - ini_set('pcre.backtrack_limit', 500000); - - if (get_magic_quotes_gpc()) { - $process = [&$_GET, &$_POST, &$_COOKIE, &$_REQUEST]; - while (list($key, $val) = each($process)) { - foreach ($val as $k => $v) { - unset($process[$key][$k]); - if (is_array($v)) { - $process[$key][stripslashes($k)] = $v; - $process[] = &$process[$key][stripslashes($k)]; - } else { - $process[$key][stripslashes($k)] = stripslashes($v); - } - } - } - unset($process); - } -} /** * @brief Retrieve the App structure diff --git a/htconfig.php b/htconfig.php index 0e838bd90d..87c1301abd 100644 --- a/htconfig.php +++ b/htconfig.php @@ -23,17 +23,19 @@ $db_data = 'mysqldatabasename'; // Use environment variables for mysql if they are set beforehand if (!empty(getenv('MYSQL_HOST')) - && !empty(getenv('MYSQL_PORT')) && (!empty(getenv('MYSQL_USERNAME')) || !empty(getenv('MYSQL_USER'))) - && !empty(getenv('MYSQL_PASSWORD')) + && !getenv('MYSQL_PASSWORD') === false && !empty(getenv('MYSQL_DATABASE'))) { - $db_host = getenv('MYSQL_HOST') . ':' . getenv('MYSQL_PORT'); + $db_host = getenv('MYSQL_HOST'); + if (!empty(getenv('MYSQL_PORT'))) { + $db_host .= ':' . getenv('MYSQL_PORT'); + } if (!empty(getenv('MYSQL_USERNAME'))) { $db_user = getenv('MYSQL_USERNAME'); - } elseif (!empty(getenv('MYSQL_USER'))) { + } else { $db_user = getenv('MYSQL_USER'); } - $db_pass = getenv('MYSQL_PASSWORD'); + $db_pass = (string) getenv('MYSQL_PASSWORD'); $db_data = getenv('MYSQL_DATABASE'); } diff --git a/include/api.php b/include/api.php index 32fe6c651d..af6f54fe60 100644 --- a/include/api.php +++ b/include/api.php @@ -16,6 +16,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\NotificationsManager; use Friendica\Core\PConfig; +use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBM; @@ -90,11 +91,15 @@ function api_source() } // Support for known clients that doesn't send a source name - if (strpos($_SERVER['HTTP_USER_AGENT'], "Twidere") !== false) { - return "Twidere"; - } + if (!empty($_SERVER['HTTP_USER_AGENT'])) { + if(strpos($_SERVER['HTTP_USER_AGENT'], "Twidere") !== false) { + return "Twidere"; + } - logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG); + logger("Unrecognized user-agent ".$_SERVER['HTTP_USER_AGENT'], LOGGER_DEBUG); + } else { + logger("Empty user-agent", LOGGER_DEBUG); + } return "api"; } @@ -193,8 +198,8 @@ function api_login(App $a) throw new UnauthorizedException("This API requires login"); } - $user = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['PHP_AUTH_PW']; + $user = defaults($_SERVER, 'PHP_AUTH_USER', ''); + $password = defaults($_SERVER, 'PHP_AUTH_PW', ''); // allow "user@server" login (but ignore 'server' part) $at = strstr($user, "@", true); @@ -258,7 +263,7 @@ function api_check_method($method) if ($method == "*") { return true; } - return (strpos($method, $_SERVER['REQUEST_METHOD']) !== false); + return (stripos($method, defaults($_SERVER, 'REQUEST_METHOD', 'GET')) !== false); } /** @@ -298,7 +303,7 @@ function api_call(App $a) //unset($_SERVER['PHP_AUTH_USER']); /// @TODO should be "true ==[=] $info['auth']", if you miss only one = character, you assign a variable (only with ==). Let's make all this even. - if ($info['auth'] === true && api_user() === false) { + if (!empty($info['auth']) && api_user() === false) { api_login($a); } @@ -475,7 +480,7 @@ function api_rss_extra(App $a, $arr, $user_info) 'base' => System::baseUrl(), 'updated' => api_date(null), 'atom_updated' => DateTimeFormat::utcNow(DateTimeFormat::ATOM), - 'language' => $user_info['language'], + 'language' => $user_info['lang'], 'logo' => System::baseUrl() . "/images/friendica-32.png", ]; @@ -571,6 +576,7 @@ function api_get_user(App $a, $contact_id = null) } } + // $called_api is the API path exploded on / and is expected to have at least 2 elements if (is_null($user) && ($a->argc > (count($called_api) - 1)) && (count($called_api) > 0)) { $argid = count($called_api); list($user, $null) = explode(".", $a->argv[$argid]); @@ -773,13 +779,13 @@ function api_get_user(App $a, $contact_id = null) $link_color = PConfig::get($ret['uid'], 'frio', 'link_color'); $bgcolor = PConfig::get($ret['uid'], 'frio', 'background_color'); } - if (!$nav_bg) { + if (empty($nav_bg)) { $nav_bg = "#708fa0"; } - if (!$link_color) { + if (empty($link_color)) { $link_color = "#6fdbe8"; } - if (!$bgcolor) { + if (empty($bgcolor)) { $bgcolor = "#ededed"; } @@ -801,12 +807,12 @@ function api_get_user(App $a, $contact_id = null) */ function api_item_get_user(App $a, $item) { - $status_user = api_get_user($a, $item["author-id"]); + $status_user = api_get_user($a, defaults($item, 'author-id', null)); - $status_user["protected"] = $item["private"]; + $status_user["protected"] = defaults($item, 'private', 0); - if ($item['thr-parent'] == $item['uri']) { - $owner_user = api_get_user($a, $item["owner-id"]); + if (defaults($item, 'thr-parent', '') == defaults($item, 'uri', '')) { + $owner_user = api_get_user($a, defaults($item, 'author-id', null)); } else { $owner_user = $status_user; } @@ -880,7 +886,6 @@ function api_create_xml(array $data, $root_element) { $childname = key($data); $data2 = array_pop($data); - $key = key($data2); $namespaces = ["" => "http://api.twitter.com", "statusnet" => "http://status.net/schema/api/1/", @@ -893,18 +898,19 @@ function api_create_xml(array $data, $root_element) } if (is_array($data2)) { + $key = key($data2); api_walk_recursive($data2, "api_reformat_xml"); - } - if ($key == "0") { - $data4 = []; - $i = 1; + if ($key == "0") { + $data4 = []; + $i = 1; - foreach ($data2 as $item) { - $data4[$i++ . ":" . $childname] = $item; + foreach ($data2 as $item) { + $data4[$i++ . ":" . $childname] = $item; + } + + $data2 = $data4; } - - $data2 = $data4; } $data3 = [$root_element => $data2]; @@ -1299,19 +1305,19 @@ function api_status_show($type) 'in_reply_to_screen_name' => $in_reply_to['screen_name'], 'user' => $user_info, $geo => null, - 'coordinates' => "", - 'place' => "", - 'contributors' => "", + 'coordinates' => '', + 'place' => '', + 'contributors' => '', 'is_quote_status' => false, 'retweet_count' => 0, 'favorite_count' => 0, 'favorited' => $lastwall['starred'] ? true : false, 'retweeted' => false, 'possibly_sensitive' => false, - 'lang' => "", + 'lang' => '', 'statusnet_html' => $converted["html"], 'statusnet_conversation_id' => $lastwall['parent'], - 'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'], + 'external_url' => System::baseUrl() . '/display/' . $lastwall['guid'], ]; if (count($converted["attachments"]) > 0) { @@ -1477,7 +1483,7 @@ function api_users_lookup($type) { $users = []; - if (x($_REQUEST['user_id'])) { + if (!empty($_REQUEST['user_id'])) { foreach (explode(',', $_REQUEST['user_id']) as $id) { if (!empty($id)) { $users[] = api_get_user(get_app(), $id); @@ -1801,20 +1807,20 @@ function api_statuses_show($type) } // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_show: ' . $id); - $conversation = (x($_REQUEST, 'conversation') ? 1 : 0); + $conversation = !empty($_REQUEST['conversation']); // try to fetch the item for the local user - or the public item, if there is no local one $uri_item = dba::selectFirst('item', ['uri'], ['id' => $id]); @@ -1874,24 +1880,24 @@ function api_conversation_show($type) } // params - $id = intval($a->argv[3]); - $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20); - $page = (x($_REQUEST, 'page') ? $_REQUEST['page'] - 1 : 0); + $id = intval(defaults($a->argv , 3 , 0)); + $since_id = intval(defaults($_REQUEST, 'since_id', 0)); + $max_id = intval(defaults($_REQUEST, 'max_id' , 0)); + $count = intval(defaults($_REQUEST, 'count' , 20)); + $page = intval(defaults($_REQUEST, 'page' , 1)) - 1; if ($page < 0) { $page = 0; } - $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); - $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); - $start = $page*$count; + $start = $page * $count; if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_conversation_show: '.$id); @@ -1954,15 +1960,15 @@ function api_statuses_repeat($type) api_get_user($a); // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_repeat: '.$id); @@ -2020,15 +2026,15 @@ function api_statuses_destroy($type) api_get_user($a); // params - $id = intval($a->argv[3]); + $id = intval(defaults($a->argv, 3, 0)); if ($id == 0) { - $id = intval($_REQUEST["id"]); + $id = intval(defaults($_REQUEST, 'id', 0)); } // Hotot workaround if ($id == 0) { - $id = intval($a->argv[4]); + $id = intval(defaults($a->argv, 4, 0)); } logger('API: api_statuses_destroy: '.$id); @@ -2205,7 +2211,7 @@ function api_favorites_create_destroy($type) // for versioned api. /// @TODO We need a better global soluton $action_argv_id = 2; - if ($a->argv[1] == "1.1") { + if (count($a->argv) > 1 && $a->argv[1] == "1.1") { $action_argv_id = 3; } @@ -2214,10 +2220,9 @@ function api_favorites_create_destroy($type) } $action = str_replace("." . $type, "", $a->argv[$action_argv_id]); if ($a->argc == $action_argv_id + 2) { - $itemid = intval($a->argv[$action_argv_id + 1]); + $itemid = intval(defaults($a->argv, $action_argv_id + 1, 0)); } else { - /// @TODO use x() to check if _REQUEST contains 'id' - $itemid = intval($_REQUEST['id']); + $itemid = intval(defaults($_REQUEST, 'id', 0)); } $item = Item::selectFirstForUser(api_user(), [], ['id' => $itemid, 'uid' => api_user()]); @@ -2340,25 +2345,33 @@ function api_format_messages($item, $recipient, $sender) { // standard meta information $ret = [ - 'id' => $item['id'], - 'sender_id' => $sender['id'] , - 'text' => "", - 'recipient_id' => $recipient['id'], - 'created_at' => api_date($item['created']), - 'sender_screen_name' => $sender['screen_name'], - 'recipient_screen_name' => $recipient['screen_name'], - 'sender' => $sender, - 'recipient' => $recipient, - 'title' => "", - 'friendica_seen' => $item['seen'], - 'friendica_parent_uri' => $item['parent-uri'], + 'id' => $item['id'], + 'sender_id' => $sender['id'] , + 'text' => "", + 'recipient_id' => $recipient['id'], + 'created_at' => api_date(defaults($item, 'created', DateTimeFormat::utcNow())), + 'sender_screen_name' => $sender['screen_name'], + 'recipient_screen_name' => $recipient['screen_name'], + 'sender' => $sender, + 'recipient' => $recipient, + 'title' => "", + 'friendica_seen' => defaults($item, 'seen', 0), + 'friendica_parent_uri' => defaults($item, 'parent-uri', ''), ]; // "uid" and "self" are only needed for some internal stuff, so remove it from here - unset($ret["sender"]["uid"]); - unset($ret["sender"]["self"]); - unset($ret["recipient"]["uid"]); - unset($ret["recipient"]["self"]); + if (isset($ret['sender']['uid'])) { + unset($ret['sender']['uid']); + } + if (isset($ret['sender']['self'])) { + unset($ret['sender']['self']); + } + if (isset($ret['recipient']['uid'])) { + unset($ret['recipient']['uid']); + } + if (isset($ret['recipient']['self'])) { + unset($ret['recipient']['self']); + } //don't send title to regular StatusNET requests to avoid confusing these apps if (x($_GET, 'getText')) { @@ -2405,8 +2418,8 @@ function api_convert_item($item) $statustext = trim($statustitle."\n\n".$statusbody); } - if (($item["network"] == NETWORK_FEED) && (strlen($statustext)> 1000)) { - $statustext = substr($statustext, 0, 1000)."... \n".$item["plink"]; + if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($statustext)> 1000)) { + $statustext = substr($statustext, 0, 1000) . "... \n" . defaults($item, 'plink', ''); } $statushtml = BBCode::convert(api_clean_attachments($body), false); @@ -2440,7 +2453,7 @@ function api_convert_item($item) } // feeds without body should contain the link - if (($item['network'] == NETWORK_FEED) && (strlen($item['body']) == 0)) { + if ((defaults($item, 'network', Protocol::PHANTOM) == Protocol::FEED) && (strlen($item['body']) == 0)) { $statushtml .= BBCode::convert($item['plink']); } @@ -2482,7 +2495,7 @@ function api_get_attachments(&$body) } } - if (strstr($_SERVER['HTTP_USER_AGENT'], "AndStatus")) { + if (strstr(defaults($_SERVER, 'HTTP_USER_AGENT', ''), "AndStatus")) { foreach ($images[0] as $orig) { $body = str_replace($orig, "", $body); } @@ -3324,18 +3337,15 @@ function api_statusnet_config($type) { $a = get_app(); - $name = $a->config['sitename']; - $server = $a->get_hostname(); - $logo = System::baseUrl() . '/images/friendica-64.png'; - $email = $a->config['admin_email']; - $closed = (($a->config['register_policy'] == REGISTER_CLOSED) ? 'true' : 'false'); - $private = ((Config::get('system', 'block_public')) ? 'true' : 'false'); - $textlimit = (string) (($a->config['max_import_size']) ? $a->config['max_import_size'] : 200000); - if ($a->config['api_import_size']) { - $textlimit = (string) $a->config['api_import_size']; - } - $ssl = ((Config::get('system', 'have_ssl')) ? 'true' : 'false'); - $sslserver = (($ssl === 'true') ? str_replace('http:', 'https:', System::baseUrl()) : ''); + $name = Config::get('config', 'sitename'); + $server = $a->get_hostname(); + $logo = System::baseUrl() . '/images/friendica-64.png'; + $email = Config::get('config', 'admin_email'); + $closed = Config::get('config', 'register_policy') == REGISTER_CLOSED ? 'true' : 'false'; + $private = Config::get('system', 'block_public') ? 'true' : 'false'; + $textlimit = (string) Config::get('config', 'api_import_size', Config::get('config', 'max_import_size', 200000)); + $ssl = Config::get('system', 'have_ssl') ? 'true' : 'false'; + $sslserver = Config::get('system', 'have_ssl') ? str_replace('http:', 'https:', System::baseUrl()) : ''; $config = [ 'site' => ['name' => $name,'server' => $server, 'theme' => 'default', 'path' => '', @@ -3457,34 +3467,40 @@ api_register_func('api/followers/ids', 'api_followers_ids', true); */ function api_direct_messages_new($type) { - $a = get_app(); if (api_user() === false) { throw new ForbiddenException(); } - if (!x($_POST, "text") || (!x($_POST, "screen_name") && !x($_POST, "user_id"))) { + if (empty($_POST["text"]) || empty($_POST["screen_name"]) && empty($_POST["user_id"])) { return; } $sender = api_get_user($a); - if ($_POST['screen_name']) { + $recipient = null; + if (!empty($_POST['screen_name'])) { $r = q( "SELECT `id`, `nurl`, `network` FROM `contact` WHERE `uid`=%d AND `nick`='%s'", intval(api_user()), dbesc($_POST['screen_name']) ); - // Selecting the id by priority, friendica first - api_best_nickname($r); + if (DBM::is_result($r)) { + // Selecting the id by priority, friendica first + api_best_nickname($r); - $recipient = api_get_user($a, $r[0]['nurl']); + $recipient = api_get_user($a, $r[0]['nurl']); + } } else { $recipient = api_get_user($a, $_POST['user_id']); } + if (empty($recipient)) { + throw new NotFoundException('Recipient not found'); + } + $replyto = ''; $sub = ''; if (x($_REQUEST, 'replyto')) { @@ -3622,17 +3638,17 @@ function api_direct_messages_box($type, $box, $verbose) throw new ForbiddenException(); } // params - $count = (x($_GET, 'count') ? $_GET['count'] : 20); - $page = (x($_REQUEST, 'page') ? $_REQUEST['page'] -1 : 0); + $count = defaults($_GET, 'count', 20); + $page = defaults($_REQUEST, 'page', 1) - 1; if ($page < 0) { $page = 0; } - $since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0); - $max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0); + $since_id = defaults($_REQUEST, 'since_id', 0); + $max_id = defaults($_REQUEST, 'max_id', 0); - $user_id = (x($_REQUEST, 'user_id') ? $_REQUEST['user_id'] : ""); - $screen_name = (x($_REQUEST, 'screen_name') ? $_REQUEST['screen_name'] : ""); + $user_id = defaults($_REQUEST, 'user_id', ''); + $screen_name = defaults($_REQUEST, 'screen_name', ''); // caller user info unset($_REQUEST["user_id"]); @@ -3656,7 +3672,7 @@ function api_direct_messages_box($type, $box, $verbose) if ($box=="sentbox") { $sql_extra = "`mail`.`from-url`='" . dbesc($profile_url) . "'"; } elseif ($box == "conversation") { - $sql_extra = "`mail`.`parent-uri`='" . dbesc($_GET["uri"]) . "'"; + $sql_extra = "`mail`.`parent-uri`='" . dbesc(defaults($_GET, 'uri', '')) . "'"; } elseif ($box == "all") { $sql_extra = "true"; } elseif ($box == "inbox") { @@ -5577,8 +5593,10 @@ function api_friendica_notification($type) if ($type == "xml") { $xmlnotes = []; - foreach ($notes as $note) { - $xmlnotes[] = ["@attributes" => $note]; + if (!empty($notes)) { + foreach ($notes as $note) { + $xmlnotes[] = ["@attributes" => $note]; + } } $notes = $xmlnotes; diff --git a/include/dba.php b/include/dba.php index 17c62b8144..9d828f8b44 100644 --- a/include/dba.php +++ b/include/dba.php @@ -1015,7 +1015,7 @@ class dba { $commands = []; // Create a key for the loop prevention - $key = $table . ':' . implode(':', array_keys($conditions)) . ':' . implode(':', $conditions); + $key = $table . ':' . json_encode($conditions); // We quit when this key already exists in the callstack. if (isset($callstack[$key])) { @@ -1042,7 +1042,7 @@ class dba { $rel_def = array_values(self::$relation[$table])[0]; // Create a key for preventing double queries - $qkey = $field . '-' . $table . ':' . implode(':', array_keys($conditions)) . ':' . implode(':', $conditions); + $qkey = $field . '-' . $table . ':' . json_encode($conditions); // When the search field is the relation field, we don't need to fetch the rows // This is useful when the leading record is already deleted in the frontend but the rest is done in the backend diff --git a/include/security.php b/include/security.php index e8a03ad0fe..dbba09172e 100644 --- a/include/security.php +++ b/include/security.php @@ -41,7 +41,7 @@ function new_cookie($time, $user = []) if ($user) { $value = json_encode(["uid" => $user["uid"], "hash" => cookie_hash($user), - "ip" => $_SERVER['REMOTE_ADDR']]); + "ip" => defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0')]); } else { $value = ""; } @@ -70,7 +70,7 @@ function authenticate_success($user_record, $login_initial = false, $interactive $_SESSION['page_flags'] = $user_record['page-flags']; $_SESSION['my_url'] = System::baseUrl() . '/profile/' . $user_record['nickname']; $_SESSION['my_address'] = $user_record['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3); - $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; + $_SESSION['addr'] = defaults($_SERVER, 'REMOTE_ADDR', '0.0.0.0'); $a->user = $user_record; diff --git a/include/text.php b/include/text.php index 04bbb67244..0066e18814 100644 --- a/include/text.php +++ b/include/text.php @@ -1156,7 +1156,7 @@ function put_item_in_cache(&$item, $update = false) $rendered_html = defaults($item, 'rendered-html', ''); if ($rendered_hash == '' - || $item["rendered-html"] == "" + || $rendered_html == "" || $rendered_hash != hash("md5", $item["body"]) || Config::get("system", "ignore_cache") ) { @@ -1176,7 +1176,7 @@ function put_item_in_cache(&$item, $update = false) $update = true; } - if ($update && ($item["id"] > 0)) { + if ($update && !empty($item["id"])) { Item::update(['rendered-html' => $item["rendered-html"], 'rendered-hash' => $item["rendered-hash"]], ['id' => $item["id"]]); } diff --git a/mod/item.php b/mod/item.php index be9fa09c47..95eaa9d78c 100644 --- a/mod/item.php +++ b/mod/item.php @@ -178,6 +178,8 @@ function item_post(App $a) { return; } + $categories = ''; + if ($orig_post) { $str_group_allow = $orig_post['allow_gid']; $str_contact_allow = $orig_post['allow_cid']; @@ -223,13 +225,13 @@ function item_post(App $a) { $str_contact_deny = perms2str($_REQUEST['contact_deny']); } - $title = notags(trim($_REQUEST['title'])); - $location = notags(trim($_REQUEST['location'])); - $coord = notags(trim($_REQUEST['coord'])); - $verb = notags(trim($_REQUEST['verb'])); - $emailcc = notags(trim($_REQUEST['emailcc'])); - $body = escape_tags(trim($_REQUEST['body'])); - $network = notags(trim(defaults($_REQUEST, 'network', NETWORK_DFRN))); + $title = notags(trim(defaults($_REQUEST, 'title' , ''))); + $location = notags(trim(defaults($_REQUEST, 'location', ''))); + $coord = notags(trim(defaults($_REQUEST, 'coord' , ''))); + $verb = notags(trim(defaults($_REQUEST, 'verb' , ''))); + $emailcc = notags(trim(defaults($_REQUEST, 'emailcc' , ''))); + $body = escape_tags(trim(defaults($_REQUEST, 'body' , ''))); + $network = notags(trim(defaults($_REQUEST, 'network' , NETWORK_DFRN))); $guid = get_guid(32); $postopts = defaults($_REQUEST, 'postopts', ''); @@ -279,15 +281,15 @@ function item_post(App $a) { } } - if (strlen($categories)) { + if (!empty($categories)) { // get the "fileas" tags for this post $filedas = file_tag_file_to_list($categories, 'file'); } // save old and new categories, so we can determine what needs to be deleted from pconfig $categories_old = $categories; - $categories = file_tag_list_to_file(trim($_REQUEST['category']), 'category'); + $categories = file_tag_list_to_file(trim(defaults($_REQUEST, 'category', '')), 'category'); $categories_new = $categories; - if (strlen($filedas)) { + if (!empty($filedas)) { // append the fileas stuff to the new categories list $categories .= file_tag_list_to_file($filedas, 'file'); } diff --git a/mod/wall_upload.php b/mod/wall_upload.php index 7067077eb7..8bf2966152 100644 --- a/mod/wall_upload.php +++ b/mod/wall_upload.php @@ -125,28 +125,36 @@ function wall_upload_post(App $a, $desktopmode = true) $filetype = $_FILES['userfile']['type']; } elseif (x($_FILES, 'media')) { - if (is_array($_FILES['media']['tmp_name'])) { - $src = $_FILES['media']['tmp_name'][0]; - } else { - $src = $_FILES['media']['tmp_name']; + if (!empty($_FILES['media']['tmp_name'])) { + if (is_array($_FILES['media']['tmp_name'])) { + $src = $_FILES['media']['tmp_name'][0]; + } else { + $src = $_FILES['media']['tmp_name']; + } } - if (is_array($_FILES['media']['name'])) { - $filename = basename($_FILES['media']['name'][0]); - } else { - $filename = basename($_FILES['media']['name']); + if (!empty($_FILES['media']['name'])) { + if (is_array($_FILES['media']['name'])) { + $filename = basename($_FILES['media']['name'][0]); + } else { + $filename = basename($_FILES['media']['name']); + } } - if (is_array($_FILES['media']['size'])) { - $filesize = intval($_FILES['media']['size'][0]); - } else { - $filesize = intval($_FILES['media']['size']); + if (!empty($_FILES['media']['size'])) { + if (is_array($_FILES['media']['size'])) { + $filesize = intval($_FILES['media']['size'][0]); + } else { + $filesize = intval($_FILES['media']['size']); + } } - if (is_array($_FILES['media']['type'])) { - $filetype = $_FILES['media']['type'][0]; - } else { - $filetype = $_FILES['media']['type']; + if (!empty($_FILES['media']['type'])) { + if (is_array($_FILES['media']['type'])) { + $filetype = $_FILES['media']['type'][0]; + } else { + $filetype = $_FILES['media']['type']; + } } } diff --git a/phpunit.xml b/phpunit.xml index b2d978aee6..b6f6247f67 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,7 @@ - + tests/ diff --git a/src/App.php b/src/App.php index f5626761e5..92ff057138 100644 --- a/src/App.php +++ b/src/App.php @@ -181,7 +181,10 @@ class App $this->process_id = uniqid('log', true); - startup(); + set_time_limit(0); + + // This has to be quite large to deal with embedded private photos + ini_set('pcre.backtrack_limit', 500000); $this->scheme = 'http'; @@ -290,7 +293,7 @@ class App $this->is_tablet = $mobile_detect->isTablet(); // Friendica-Client - $this->is_friendica_app = ($_SERVER['HTTP_USER_AGENT'] == 'Apache-HttpClient/UNAVAILABLE (java 1.4)'); + $this->is_friendica_app = isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'Apache-HttpClient/UNAVAILABLE (java 1.4)'; // Register template engines $this->register_template_engine('Friendica\Render\FriendicaSmartyEngine'); @@ -863,7 +866,7 @@ class App return; } - array_unshift($args, ((x($this->config, 'php_path')) && (strlen($this->config['php_path'])) ? $this->config['php_path'] : 'php')); + array_unshift($args, $this->getConfigValue('config', 'php_path', 'php')); for ($x = 0; $x < count($args); $x ++) { $args[$x] = escapeshellarg($args[$x]); @@ -875,7 +878,7 @@ class App return; } - if (Config::get('system', 'proc_windows')) { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->get_basepath()); } else { $resource = proc_open($cmdline . ' &', [], $foo, $this->get_basepath()); diff --git a/src/Core/System.php b/src/Core/System.php index ded781da83..abc39e5a2a 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -72,6 +72,7 @@ class System extends BaseObject } } elseif (!in_array($func['function'], $ignore)) { $callstack[] = $func['function']; + $func['class'] = ''; $previous = $func; } } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index d3ce350a72..7bb9b18aec 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -412,7 +412,7 @@ class DBStructure $field_definition = $database[$name]["fields"][$fieldname]; // Define the default collation if not given - if (!isset($parameters['Collation']) && !is_null($field_definition['Collation'])) { + if (!isset($parameters['Collation']) && !empty($field_definition['Collation'])) { $parameters['Collation'] = 'utf8mb4_general_ci'; } else { $parameters['Collation'] = null; @@ -536,26 +536,26 @@ class DBStructure private static function FieldCommand($parameters, $create = true) { $fieldstruct = $parameters["type"]; - if (!is_null($parameters["Collation"])) { + if (!empty($parameters["Collation"])) { $fieldstruct .= " COLLATE ".$parameters["Collation"]; } - if ($parameters["not null"]) { + if (!empty($parameters["not null"])) { $fieldstruct .= " NOT NULL"; } - if (isset($parameters["default"])) { + if (!empty($parameters["default"])) { if (strpos(strtolower($parameters["type"]),"int")!==false) { $fieldstruct .= " DEFAULT ".$parameters["default"]; } else { $fieldstruct .= " DEFAULT '".$parameters["default"]."'"; } } - if ($parameters["extra"] != "") { + if (!empty($parameters["extra"])) { $fieldstruct .= " ".$parameters["extra"]; } - if (!is_null($parameters["comment"])) { + if (!empty($parameters["comment"])) { $fieldstruct .= " COMMENT '".dbesc($parameters["comment"])."'"; } @@ -579,7 +579,7 @@ class DBStructure } } - if (!is_null($structure["indexes"])) { + if (!empty($structure["indexes"])) { foreach ($structure["indexes"] AS $indexname => $fieldnames) { $sql_index = self::createIndex($indexname, $fieldnames, ""); if (!is_null($sql_index)) { @@ -588,11 +588,11 @@ class DBStructure } } - if (!is_null($structure["engine"])) { + if (!empty($structure["engine"])) { $engine = " ENGINE=" . $structure["engine"]; } - if (!is_null($structure["comment"])) { + if (!empty($structure["comment"])) { $comment = " COMMENT='" . dbesc($structure["comment"]) . "'"; } diff --git a/src/Model/Conversation.php b/src/Model/Conversation.php index 17f151fe03..69bbc3bb6d 100644 --- a/src/Model/Conversation.php +++ b/src/Model/Conversation.php @@ -61,7 +61,7 @@ class Conversation unset($old_conv['source']); } // Update structure data all the time but the source only when its from a better protocol. - if (($old_conv['protocol'] < $conversation['protocol']) && ($old_conv['protocol'] != 0)) { + if (isset($conversation['protocol']) && isset($conversation['source']) && ($old_conv['protocol'] < $conversation['protocol']) && ($old_conv['protocol'] != 0)) { unset($conversation['protocol']); unset($conversation['source']); } diff --git a/src/Model/Item.php b/src/Model/Item.php index d31d7c1323..664a8e9b29 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -809,7 +809,9 @@ class Item extends BaseObject // If item has attachments, drop them foreach (explode(", ", $item['attach']) as $attach) { preg_match("|attach/(\d+)|", $attach, $matches); - dba::delete('attach', ['id' => $matches[1], 'uid' => $item['uid']]); + if (is_array($matches) && count($matches) > 1) { + dba::delete('attach', ['id' => $matches[1], 'uid' => $item['uid']]); + } } // Delete tags that had been attached to other items @@ -1997,7 +1999,7 @@ class Item extends BaseObject Contact::unmarkForArchival($contact); } - $update = (!$arr['private'] && (($arr["author-link"] === $arr["owner-link"]) || ($arr["parent-uri"] === $arr["uri"]))); + $update = (!$arr['private'] && ((defaults($arr, 'author-link', '') === defaults($arr, 'owner-link', '')) || ($arr["parent-uri"] === $arr["uri"]))); // Is it a forum? Then we don't care about the rules from above if (!$update && ($arr["network"] == NETWORK_DFRN) && ($arr["parent-uri"] === $arr["uri"])) { diff --git a/src/Network/Probe.php b/src/Network/Probe.php index 5f665814b4..8e44c8a50b 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -109,6 +109,7 @@ class Probe $redirects = 0; logger("Probing for ".$host, LOGGER_DEBUG); + $xrd = null; $ret = Network::curl($ssl_url, false, $redirects, ['timeout' => $xrd_timeout, 'accept_content' => 'application/xrd+xml']); if ($ret['success']) { @@ -1510,6 +1511,7 @@ class Probe return false; } $feed = $ret['body']; + $dummy1 = $dummy2 = $dummy3 = null; $feed_data = Feed::import($feed, $dummy1, $dummy2, $dummy3, true); if (!$feed_data) { diff --git a/tests/ApiTest.php b/tests/ApiTest.php index c21f651d5f..c8443512c8 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -29,6 +29,10 @@ class ApiTest extends DatabaseTest global $a; parent::setUp(); + // Reusable App object + $this->app = new App(__DIR__.'/../'); + $a = $this->app; + // User data that the test database is populated with $this->selfUser = [ 'id' => 42, @@ -36,6 +40,12 @@ class ApiTest extends DatabaseTest 'nick' => 'selfcontact', 'nurl' => 'http://localhost/profile/selfcontact' ]; + $this->friendUser = [ + 'id' => 44, + 'name' => 'Friend contact', + 'nick' => 'friendcontact', + 'nurl' => 'http://localhost/profile/friendcontact' + ]; $this->otherUser = [ 'id' => 43, 'name' => 'othercontact', @@ -53,10 +63,6 @@ class ApiTest extends DatabaseTest 'uid' => $this->selfUser['id'] ]; - // Reusable App object - $this->app = new App(__DIR__.'/../'); - $a = $this->app; - // Default config Config::set('config', 'hostname', 'localhost'); Config::set('system', 'throttle_limit_day', 100); @@ -481,7 +487,7 @@ class ApiTest extends DatabaseTest $this->app->query_string = 'api_path.rss'; $this->assertEquals( - ''.PHP_EOL. + ''."\n". 'some_data', api_call($this->app) ); @@ -505,7 +511,7 @@ class ApiTest extends DatabaseTest $this->app->query_string = 'api_path.atom'; $this->assertEquals( - ''.PHP_EOL. + ''."\n". 'some_data', api_call($this->app) ); @@ -571,14 +577,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('xml', new HTTPException('error_message')) ); } @@ -591,14 +597,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithRss() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('rss', new HTTPException('error_message')) ); } @@ -611,14 +617,14 @@ class ApiTest extends DatabaseTest public function testApiErrorWithAtom() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' error_message'.PHP_EOL. - ' 200 Friendica\Network\HTTP'.PHP_EOL. - ' '.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' error_message'."\n". + ' 200 Friendica\Network\HTTP'."\n". + ' '."\n". + ''."\n", api_error('atom', new HTTPException('error_message')) ); } @@ -629,7 +635,7 @@ class ApiTest extends DatabaseTest */ public function testApiRssExtra() { - $user_info = ['url' => 'user_url']; + $user_info = ['url' => 'user_url', 'lang' => 'en']; $result = api_rss_extra($this->app, [], $user_info); $this->assertEquals($user_info, $result['$user']); $this->assertEquals($user_info['url'], $result['$rss']['alternate']); @@ -818,7 +824,7 @@ class ApiTest extends DatabaseTest public function testApiGetUserWithCalledApi() { global $called_api; - $called_api = ['api_path']; + $called_api = ['api', 'api_path']; $this->assertSelfUser(api_get_user($this->app)); } @@ -853,7 +859,6 @@ class ApiTest extends DatabaseTest $this->assertSelfUser(api_get_user($this->app, 0)); } - /** * Test the api_item_get_user() function. * @return void @@ -957,12 +962,12 @@ class ApiTest extends DatabaseTest public function testApiCreateXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' some_data'."\n". + ''."\n", api_create_xml(['data' => ['some_data']], 'root_element') ); } @@ -974,10 +979,10 @@ class ApiTest extends DatabaseTest public function testApiCreateXmlWithoutNamespaces() { $this->assertEquals( - ''.PHP_EOL. - ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + ''."\n". + ''."\n". + ' some_data'."\n". + ''."\n", api_create_xml(['data' => ['some_data']], 'ok') ); } @@ -999,12 +1004,12 @@ class ApiTest extends DatabaseTest public function testApiFormatDataWithXml() { $this->assertEquals( - ''.PHP_EOL. + ''."\n". ''.PHP_EOL. - ' some_data'.PHP_EOL. - ''.PHP_EOL, + 'xmlns:georss="http://www.georss.org/georss">'."\n". + ' some_data'."\n". + ''."\n", api_format_data('root_element', 'xml', ['data' => ['some_data']]) ); } @@ -1073,6 +1078,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; @@ -1110,6 +1116,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; @@ -1217,6 +1224,7 @@ class ApiTest extends DatabaseTest 'width' => 666, 'height' => 666, 'tmp_name' => $this->getTempImage(), + 'name' => 'spacer.png', 'type' => 'image/png' ] ]; @@ -1833,6 +1841,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroy() { + $this->app->argv = ['api', '1.1', 'favorites', 'create']; + $this->app->argc = count($this->app->argv); api_favorites_create_destroy('json'); } @@ -1843,9 +1853,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithInvalidId() { - // This triggers a very specific condition ($action_argv_id + 2) - $this->app->argv[1] = '1.1'; - $this->app->argc = 5; + $this->app->argv = ['api', '1.1', 'favorites', 'create', '12.json']; + $this->app->argc = count($this->app->argv); api_favorites_create_destroy('json'); } @@ -1856,8 +1865,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithInvalidAction() { - $this->app->argv[1] = '1.1'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'change.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 1; api_favorites_create_destroy('json'); } @@ -1868,9 +1877,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithCreateAction() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'create'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'create.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); @@ -1882,9 +1890,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithCreateActionAndRss() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'create'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'create.rss']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('rss'); $this->assertXml($result, 'status'); @@ -1896,9 +1903,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithDestroyAction() { - $this->app->argv[1] = '1.1'; - $this->app->argv[3] = 'destroy'; - $this->app->argc = 10; + $this->app->argv = ['api', '1.1', 'favorites', 'destroy.json']; + $this->app->argc = count($this->app->argv); $_REQUEST['id'] = 3; $result = api_favorites_create_destroy('json'); $this->assertStatus($result['status']); @@ -1911,6 +1917,8 @@ class ApiTest extends DatabaseTest */ public function testApiFavoritesCreateDestroyWithoutAuthenticatedUser() { + $this->app->argv = ['api', '1.1', 'favorites', 'create.json']; + $this->app->argc = count($this->app->argv); $_SESSION['authenticated'] = false; api_favorites_create_destroy('json'); } @@ -1962,7 +1970,7 @@ class ApiTest extends DatabaseTest ['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 3, 'screen_name' => 'sender_name'] ); - $this->assertEquals('item_title'.PHP_EOL.'item_body', $result['text']); + $this->assertEquals('item_title'."\n".'item_body', $result['text']); $this->assertEquals(1, $result['id']); $this->assertEquals(2, $result['recipient_id']); $this->assertEquals(3, $result['sender_id']); @@ -2014,8 +2022,8 @@ class ApiTest extends DatabaseTest ['id' => 2, 'screen_name' => 'recipient_name'], ['id' => 3, 'screen_name' => 'sender_name'] ); - $this->assertNull($result['sender']); - $this->assertNull($result['recipient']); + $this->assertTrue(!isset($result['sender'])); + $this->assertTrue(!isset($result['recipient'])); } /** @@ -2051,7 +2059,8 @@ class ApiTest extends DatabaseTest 'repellat officia illum quos impedit quam iste esse unde qui '. 'suscipit aut facilis ut inventore omnis exercitationem quo magnam '. 'consequatur maxime aut illum soluta quaerat natus unde aspernatur '. - 'et sed beatae nihil ullam temporibus corporis ratione blanditiis' + 'et sed beatae nihil ullam temporibus corporis ratione blanditiis', + 'plink' => 'item_plink' ] ); $this->assertStringStartsWith('item_title', $result['text']); @@ -2108,7 +2117,7 @@ class ApiTest extends DatabaseTest */ public function testApiGetAttachmentsWithImage() { - $body = '[img]img_url[/img]'; + $body = '[img]http://via.placeholder.com/1x1.png[/img]'; $this->assertInternalType('array', api_get_attachments($body)); } @@ -2119,7 +2128,7 @@ class ApiTest extends DatabaseTest public function testApiGetAttachmentsWithImageAndAndStatus() { $_SERVER['HTTP_USER_AGENT'] = 'AndStatus'; - $body = '[img]img_url[/img]'; + $body = '[img]http://via.placeholder.com/1x1.png[/img]'; $this->assertInternalType('array', api_get_attachments($body)); } @@ -2155,7 +2164,7 @@ class ApiTest extends DatabaseTest public function testApiFormatItemsEmbededImages() { $this->assertEquals( - 'text http://localhost/display/item_guid', + 'text ' . \Friendica\Core\System::baseUrl() . '/display/item_guid', api_format_items_embeded_images(['guid' => 'item_guid'], 'text data:image/foo') ); } @@ -2196,7 +2205,7 @@ class ApiTest extends DatabaseTest */ public function testApiFormatItemsActivities() { - $item = []; + $item = ['uid' => 0, 'uri' => '']; $result = api_format_items_activities($item); $this->assertArrayHasKey('like', $result); $this->assertArrayHasKey('dislike', $result); @@ -2211,7 +2220,7 @@ class ApiTest extends DatabaseTest */ public function testApiFormatItemsActivitiesWithXml() { - $item = []; + $item = ['uid' => 0, 'uri' => '']; $result = api_format_items_activities($item, 'xml'); $this->assertArrayHasKey('friendica:like', $result); $this->assertArrayHasKey('friendica:dislike', $result); @@ -2325,10 +2334,16 @@ class ApiTest extends DatabaseTest [ 'item_network' => 'item_network', 'source' => 'web', - 'coord' => '5 7' + 'coord' => '5 7', + 'body' => '', + 'verb' => '', + 'author-id' => 43, + 'author-network' => \Friendica\Core\Protocol::DFRN, + 'author-link' => 'http://localhost/profile/othercontact', + 'plink' => '', ] ]; - $result = api_format_items($items, [], true); + $result = api_format_items($items, ['id' => 0], true); foreach ($result as $status) { $this->assertStatus($status); } @@ -2342,10 +2357,16 @@ class ApiTest extends DatabaseTest { $items = [ [ - 'coord' => '5 7' + 'coord' => '5 7', + 'body' => '', + 'verb' => '', + 'author-id' => 43, + 'author-network' => \Friendica\Core\Protocol::DFRN, + 'author-link' => 'http://localhost/profile/othercontact', + 'plink' => '', ] ]; - $result = api_format_items($items, [], true, 'xml'); + $result = api_format_items($items, ['id' => 0], true, 'xml'); foreach ($result as $status) { $this->assertStatus($status); } @@ -2389,7 +2410,6 @@ class ApiTest extends DatabaseTest */ public function testApiHelpTestWithXml() { - $this->markTestIncomplete('Triggers this error: "key() expects parameter 1 to be array, string given"'); $result = api_help_test('xml'); $this->assertXml($result, 'ok'); } @@ -2615,7 +2635,7 @@ class ApiTest extends DatabaseTest $result = api_statusnet_config('json'); $this->assertEquals('localhost', $result['config']['site']['server']); $this->assertEquals('default', $result['config']['site']['theme']); - $this->assertEquals('http://localhost/images/friendica-64.png', $result['config']['site']['logo']); + $this->assertEquals(\Friendica\Core\System::baseUrl() . '/images/friendica-64.png', $result['config']['site']['logo']); $this->assertTrue($result['config']['site']['fancy']); $this->assertEquals('en', $result['config']['site']['language']); $this->assertEquals('UTC', $result['config']['site']['timezone']); @@ -2725,7 +2745,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithScreenName() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $result = api_direct_messages_new('json'); $this->assertEquals(1, $result['direct_message']['id']); $this->assertContains('message_text', $result['direct_message']['text']); @@ -2740,7 +2760,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithTitle() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $_REQUEST['title'] = 'message_title'; $result = api_direct_messages_new('json'); $this->assertEquals(1, $result['direct_message']['id']); @@ -2757,7 +2777,7 @@ class ApiTest extends DatabaseTest public function testApiDirectMessagesNewWithRss() { $_POST['text'] = 'message_text'; - $_POST['screen_name'] = $this->otherUser['nick']; + $_POST['screen_name'] = $this->friendUser['nick']; $result = api_direct_messages_new('rss'); $this->assertXml($result, 'direct-messages'); } @@ -3357,7 +3377,7 @@ class ApiTest extends DatabaseTest */ public function testApiShareAsRetweet() { - $item = []; + $item = ['body' => '']; $result = api_share_as_retweet($item); $this->assertFalse($result); } @@ -3397,7 +3417,7 @@ class ApiTest extends DatabaseTest */ public function testApiInReplyTo() { - $result = api_in_reply_to([]); + $result = api_in_reply_to(['id' => 0, 'parent' => 0, 'uri' => '', 'thr-parent' => '']); $this->assertArrayHasKey('status_id', $result); $this->assertArrayHasKey('user_id', $result); $this->assertArrayHasKey('status_id_str', $result); @@ -3562,7 +3582,8 @@ class ApiTest extends DatabaseTest */ public function testApiFriendicaNotificationWithArgumentCount() { - $this->app->argc = 3; + $this->app->argv = ['api', 'friendica', 'notification']; + $this->app->argc = count($this->app->argv); $result = api_friendica_notification('json'); $this->assertEquals(['note' => false], $result); } @@ -3573,8 +3594,8 @@ class ApiTest extends DatabaseTest */ public function testApiFriendicaNotificationWithXmlResult() { - $this->markTestIncomplete('Fails with "Invalid argument supplied for foreach()".'); - $this->app->argc = 3; + $this->app->argv = ['api', 'friendica', 'notification']; + $this->app->argc = count($this->app->argv); $result = api_friendica_notification('xml'); $this->assertXml($result, 'notes'); } diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 12150932c9..e79e9237be 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -20,6 +20,54 @@ abstract class DatabaseTest extends TestCase use TestCaseTrait; + /** + * Renames an eventually existing .htconfig.php to .htconfig.php.tmp + * Creates a new .htconfig.php for bin/worker.php execution + */ + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + + $base_config_file_name = 'htconfig.php'; + $config_file_name = '.htconfig.php'; + + $base_config_file_path = stream_resolve_include_path($base_config_file_name); + $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + $config_file_path_tmp = $config_file_path . '.tmp'; + + if (file_exists($config_file_path)) { + rename($config_file_path, $config_file_path_tmp); + } + + $config_string = file_get_contents($base_config_file_path); + + $config_string = str_replace('die(', '// die(', $config_string); + + file_put_contents($config_file_path, $config_string); + } + + /** + * Delete the created .htconfig.php + * Renames an eventually existing .htconfig.php.tmp to .htconfig.php + */ + public static function tearDownAfterClass() + { + $base_config_file_name = 'htconfig.php'; + $config_file_name = '.htconfig.php'; + + $base_config_file_path = stream_resolve_include_path($base_config_file_name); + $config_file_path = dirname($base_config_file_path) . DIRECTORY_SEPARATOR . $config_file_name; + $config_file_path_tmp = $config_file_path . '.tmp'; + + if (file_exists($config_file_path)) { + unlink($config_file_path); + } + + if (file_exists($config_file_path_tmp)) { + rename($config_file_path_tmp, $config_file_path); + } + } + /** * Get database connection. * @@ -34,21 +82,23 @@ abstract class DatabaseTest extends TestCase protected function getConnection() { if (!dba::$connected) { - dba::connect('localhost', getenv('USER'), getenv('PASS'), getenv('DB')); + dba::connect(getenv('MYSQL_HOST') . ':' . getenv('MYSQL_PORT'), getenv('MYSQL_USERNAME'), getenv('MYSQL_PASSWORD'), getenv('MYSQL_DATABASE')); if (dba::$connected) { $app = get_app(); // We need to do this in order to disable logging - $app->module = 'install'; + $app->mode = \Friendica\App::MODE_INSTALL; // Create database structure DBStructure::update(false, true, true); + + $app->mode = \Friendica\App::MODE_NORMAL; } else { - $this->markTestSkipped('Could not connect to the database.'); + $this->markTestSkipped('Could not connect to the database. Please check the MYSQL_* environment variables.'); } } - return $this->createDefaultDBConnection(dba::get_db(), getenv('DB')); + return $this->createDefaultDBConnection(dba::get_db(), getenv('MYSQL_DATABASE')); } /** diff --git a/tests/datasets/api.yml b/tests/datasets/api.yml index 14053c3e86..25c9dade60 100644 --- a/tests/datasets/api.yml +++ b/tests/datasets/api.yml @@ -48,7 +48,7 @@ contact: network: dfrn - id: 44 - uid: 0 + uid: 42 name: Friend contact nick: friendcontact self: 0