X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=include%2Fapi.php;h=2d41cb986a4e5706c42fa6205bc8926816ae4221;hb=96a6c098bccfc4cdd19c1be8a04a60b8a5e2f76b;hp=a7853ed32be9445de3023d1bcfdea74c312307f1;hpb=57d888f3e716119488722ee6256ccb5da2492d7d;p=friendica.git diff --git a/include/api.php b/include/api.php index a7853ed32b..2d41cb986a 100644 --- a/include/api.php +++ b/include/api.php @@ -1,20 +1,28 @@ ". * Some clients doesn't send a source param, we support ones we know * (only Twidere, atm) * + * @brief Get source name from API client + * * @return string * Client source name, default to "api" if unset/unknown */ @@ -106,13 +108,13 @@ function api_source() function api_date($str) { // Wed May 23 06:01:13 +0000 2007 - return datetime_convert('UTC', 'UTC', $str, "D M d H:i:s +0000 Y"); + return DateTimeFormat::utc($str, "D M d H:i:s +0000 Y"); } /** - * @brief Register API endpoint + * Register a function to be the endpoint for defined API path. * - * Register a function to be the endpont for defined API path. + * @brief Register API endpoint * * @param string $path API URL path, relative to System::baseUrl() * @param string $func Function name to call on path request @@ -125,28 +127,28 @@ function api_register_func($path, $func, $auth = false, $method = API_METHOD_ANY { global $API; - $API[$path] = array( + $API[$path] = [ 'func' => $func, 'auth' => $auth, 'method' => $method, - ); + ]; // Workaround for hotot $path = str_replace("api/", "api/1.1/", $path); - $API[$path] = array( + $API[$path] = [ 'func' => $func, 'auth' => $auth, 'method' => $method, - ); + ]; } /** - * @brief Login API user - * * Log in user via OAuth1 or Simple HTTP Auth. * Simple Auth allow username in form of
user@server
, ignoring server part * + * @brief Login API user + * * @param object $a App * @hook 'authenticate' * array $addon_auth @@ -165,7 +167,7 @@ function api_login(App $a) list($consumer, $token) = $oauth1->verify_request(OAuthRequest::from_request()); if (!is_null($token)) { $oauth1->loginUser($token->uid); - call_hooks('logged_in', $a->user); + Addon::callHooks('logged_in', $a->user); return; } echo __FILE__.__LINE__.__FUNCTION__ . "
";
@@ -186,7 +188,7 @@ function api_login(App $a)
 	}
 
 	if (!x($_SERVER, 'PHP_AUTH_USER')) {
-		logger('API_login: ' . print_r($_SERVER,true), LOGGER_DEBUG);
+		logger('API_login: ' . print_r($_SERVER, true), LOGGER_DEBUG);
 		header('WWW-Authenticate: Basic realm="Friendica"');
 		throw new UnauthorizedException("This API requires login");
 	}
@@ -203,30 +205,30 @@ function api_login(App $a)
 	// next code from mod/auth.php. needs better solution
 	$record = null;
 
-	$addon_auth = array(
+	$addon_auth = [
 		'username' => trim($user),
 		'password' => trim($password),
 		'authenticated' => 0,
 		'user_record' => null,
-	);
+	];
 
 	/*
-		* A plugin indicates successful login by setting 'authenticated' to non-zero value and returning a user record
-		* Plugins should never set 'authenticated' except to indicate success - as hooks may be chained
-		* and later plugins should not interfere with an earlier one that succeeded.
-		*/
-	call_hooks('authenticate', $addon_auth);
+	* An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record
+	* Addons should never set 'authenticated' except to indicate success - as hooks may be chained
+	* and later addons should not interfere with an earlier one that succeeded.
+	*/
+	Addon::callHooks('authenticate', $addon_auth);
 
-	if (($addon_auth['authenticated']) && (count($addon_auth['user_record']))) {
+	if ($addon_auth['authenticated'] && count($addon_auth['user_record'])) {
 		$record = $addon_auth['user_record'];
 	} else {
 		$user_id = User::authenticate(trim($user), trim($password));
 		if ($user_id) {
-			$record = dba::select('user', [], ['uid' => $user_id], ['limit' => 1]);
+			$record = dba::selectFirst('user', [], ['uid' => $user_id]);
 		}
 	}
 
-	if ((! $record) || (! count($record))) {
+	if (!DBM::is_result($record)) {
 		logger('API_login failure: ' . print_r($_SERVER, true), LOGGER_DEBUG);
 		header('WWW-Authenticate: Basic realm="Friendica"');
 		//header('HTTP/1.0 401 Unauthorized');
@@ -238,16 +240,16 @@ function api_login(App $a)
 
 	$_SESSION["allow_api"] = true;
 
-	call_hooks('logged_in', $a->user);
+	Addon::callHooks('logged_in', $a->user);
 }
 
 /**
- * @brief Check HTTP method of called API
- *
  * API endpoints can define which HTTP method to accept when called.
  * This function check the current HTTP method agains endpoint
  * registered method.
  *
+ * @brief Check HTTP method of called API
+ *
  * @param string $method Required methods, uppercase, separated by comma
  * @return bool
  */
@@ -260,10 +262,10 @@ function api_check_method($method)
 }
 
 /**
- * @brief Main API entry point
- *
  * Authenticate user, call registered API function, set HTTP headers
  *
+ * @brief Main API entry point
+ *
  * @param object $a App
  * @return string API call result
  */
@@ -304,7 +306,7 @@ function api_call(App $a)
 				logger('API parameters: ' . print_r($_REQUEST, true));
 
 				$stamp =  microtime(true);
-				$r = call_user_func($info['func'], $type);
+				$return = call_user_func($info['func'], $type);
 				$duration = (float) (microtime(true) - $stamp);
 				logger("API call duration: " . round($duration, 2) . "\t" . $a->query_string, LOGGER_DEBUG);
 
@@ -314,12 +316,16 @@ function api_call(App $a)
 					/// @TODO round() really everywhere?
 					logger(
 						parse_url($a->query_string, PHP_URL_PATH) . ": " . sprintf(
-							"Database: %s/%s, Network: %s, I/O: %s, Other: %s, Total: %s",
+							"Database: %s/%s, Cache %s/%s, Network: %s, I/O: %s, Other: %s, Total: %s",
 							round($a->performance["database"] - $a->performance["database_write"], 3),
 							round($a->performance["database_write"], 3),
+							round($a->performance["cache"], 3),
+							round($a->performance["cache_write"], 3),
 							round($a->performance["network"], 2),
 							round($a->performance["file"], 2),
-							round($duration - ($a->performance["database"] + $a->performance["network"]	+ $a->performance["file"]), 2),
+							round($duration - ($a->performance["database"]
+								+ $a->performance["cache"] + $a->performance["cache_write"]
+								+ $a->performance["network"] + $a->performance["file"]), 2),
 							round($duration, 2)
 						),
 						LOGGER_DEBUG
@@ -341,6 +347,21 @@ function api_call(App $a)
 							}
 						}
 
+						$o = "Cache Read:\n";
+						foreach ($a->callstack["cache"] as $func => $time) {
+							$time = round($time, 3);
+							if ($time > 0) {
+								$o .= $func . ": " . $time . "\n";
+							}
+						}
+						$o .= "\nCache Write:\n";
+						foreach ($a->callstack["cache_write"] as $func => $time) {
+							$time = round($time, 3);
+							if ($time > 0) {
+								$o .= $func . ": " . $time . "\n";
+							}
+						}
+
 						$o .= "\nNetwork:\n";
 						foreach ($a->callstack["network"] as $func => $time) {
 							$time = round($time, 3);
@@ -352,7 +373,7 @@ function api_call(App $a)
 					}
 				}
 
-				if (false === $r) {
+				if (false === $return) {
 					/*
 						* api function returned false withour throw an
 						* exception. This should not happend, throw a 500
@@ -363,26 +384,27 @@ function api_call(App $a)
 				switch ($type) {
 					case "xml":
 						header("Content-Type: text/xml");
-						return $r;
 						break;
 					case "json":
 						header("Content-Type: application/json");
-						foreach ($r as $rr)
+						foreach ($return as $rr) {
 							$json = json_encode($rr);
-							if (x($_GET, 'callback')) {
-								$json = $_GET['callback'] . "(" . $json . ")";
-							}
-							return $json;
+						}
+						if (x($_GET, 'callback')) {
+							$json = $_GET['callback'] . "(" . $json . ")";
+						}
+						$return = $json;
 						break;
 					case "rss":
 						header("Content-Type: application/rss+xml");
-						return '' . "\n" . $r;
+						$return  = '' . "\n" . $return;
 						break;
 					case "atom":
 						header("Content-Type: application/atom+xml");
-						return '' . "\n" . $r;
+						$return = '' . "\n" . $return;
 						break;
 				}
+				return $return;
 			}
 		}
 
@@ -399,7 +421,7 @@ function api_call(App $a)
  *
  * @param string $type Return type (xml, json, rss, as)
  * @param object $e    HTTPException Error object
- * @return strin error message formatted as $type
+ * @return string error message formatted as $type
  */
 function api_error($type, $e)
 {
@@ -408,30 +430,29 @@ function api_error($type, $e)
 	$error = ($e->getMessage() !== "" ? $e->getMessage() : $e->httpdesc);
 	/// @TODO:  https://dev.twitter.com/overview/api/response-codes
 
-	$error = array("error" => $error,
+	$error = ["error" => $error,
 			"code" => $e->httpcode . " " . $e->httpdesc,
-			"request" => $a->query_string);
+			"request" => $a->query_string];
 
-	$ret = api_format_data('status', $type, array('status' => $error));
+	$return = api_format_data('status', $type, ['status' => $error]);
 
 	switch ($type) {
 		case "xml":
 			header("Content-Type: text/xml");
-			return $ret;
 			break;
 		case "json":
 			header("Content-Type: application/json");
-			return json_encode($ret);
+			$return = json_encode($return);
 			break;
 		case "rss":
 			header("Content-Type: application/rss+xml");
-			return $ret;
 			break;
 		case "atom":
 			header("Content-Type: application/atom+xml");
-			return $ret;
 			break;
 	}
+
+	return $return;
 }
 
 /**
@@ -450,15 +471,15 @@ function api_rss_extra(App $a, $arr, $user_info)
 	}
 
 	$arr['$user'] = $user_info;
-	$arr['$rss'] = array(
+	$arr['$rss'] = [
 		'alternate'    => $user_info['url'],
 		'self'         => System::baseUrl() . "/" . $a->query_string,
 		'base'         => System::baseUrl(),
 		'updated'      => api_date(null),
-		'atom_updated' => datetime_convert('UTC', 'UTC', 'now', ATOM_TIME),
+		'atom_updated' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
 		'language'     => $user_info['language'],
 		'logo'         => System::baseUrl() . "/images/friendica-32.png",
-	);
+	];
 
 	return $arr;
 }
@@ -473,7 +494,7 @@ function api_rss_extra(App $a, $arr, $user_info)
  */
 function api_unique_id_to_nurl($id)
 {
-	$r = dba::select('contact', array('nurl'), array('uid' => 0, 'id' => $id), array('limit' => 1));
+	$r = dba::selectFirst('contact', ['nurl'], ['uid' => 0, 'id' => $id]);
 
 	if (DBM::is_result($r)) {
 		return $r["nurl"];
@@ -495,7 +516,6 @@ function api_get_user(App $a, $contact_id = null)
 	$user = null;
 	$extra_query = "";
 	$url = "";
-	$nick = "";
 
 	logger("api_get_user: Fetching user data for user ".$contact_id, LOGGER_DEBUG);
 
@@ -539,7 +559,6 @@ function api_get_user(App $a, $contact_id = null)
 	}
 	if (is_null($user) && x($_GET, 'screen_name')) {
 		$user = dbesc($_GET['screen_name']);
-		$nick = $user;
 		$extra_query = "AND `contact`.`nick` = '%s' ";
 		if (api_user() !== false) {
 			$extra_query .= "AND `contact`.`uid`=".intval(api_user());
@@ -548,7 +567,6 @@ function api_get_user(App $a, $contact_id = null)
 
 	if (is_null($user) && x($_GET, 'profileurl')) {
 		$user = dbesc(normalise_link($_GET['profileurl']));
-		$nick = $user;
 		$extra_query = "AND `contact`.`nurl` = '%s' ";
 		if (api_user() !== false) {
 			$extra_query .= "AND `contact`.`uid`=".intval(api_user());
@@ -572,7 +590,6 @@ function api_get_user(App $a, $contact_id = null)
 			}
 		} else {
 			$user = dbesc($user);
-			$nick = $user;
 			$extra_query = "AND `contact`.`nick` = '%s' ";
 			if (api_user() !== false) {
 				$extra_query .= "AND `contact`.`uid`=" . intval(api_user());
@@ -607,21 +624,21 @@ function api_get_user(App $a, $contact_id = null)
 
 	// if the contact wasn't found, fetch it from the contacts with uid = 0
 	if (!DBM::is_result($uinfo)) {
-		$r = array();
+		$r = [];
 
 		if ($url != "") {
 			$r = q("SELECT * FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s' LIMIT 1", dbesc(normalise_link($url)));
 		}
 
 		if (DBM::is_result($r)) {
-			$network_name = network_to_name($r[0]['network'], $r[0]['url']);
+			$network_name = ContactSelector::networkToName($r[0]['network'], $r[0]['url']);
 
 			// If no nick where given, extract it from the address
 			if (($r[0]['nick'] == "") || ($r[0]['name'] == $r[0]['nick'])) {
 				$r[0]['nick'] = api_get_nick($r[0]["url"]);
 			}
 
-			$ret = array(
+			$ret = [
 				'id' => $r[0]["id"],
 				'id_str' => (string) $r[0]["id"],
 				'name' => $r[0]["name"],
@@ -655,7 +672,7 @@ function api_get_user(App $a, $contact_id = null)
 				'cid' => Contact::getIdForURL($r[0]["url"], api_user(), true),
 				'self' => 0,
 				'network' => $r[0]["network"],
-			);
+			];
 
 			return $ret;
 		} else {
@@ -738,17 +755,31 @@ function api_get_user(App $a, $contact_id = null)
 		$uinfo[0]['nick'] = api_get_nick($uinfo[0]["url"]);
 	}
 
-	$network_name = network_to_name($uinfo[0]['network'], $uinfo[0]['url']);
+	$network_name = ContactSelector::networkToName($uinfo[0]['network'], $uinfo[0]['url']);
 
 	$pcontact_id  = Contact::getIdForURL($uinfo[0]['url'], 0, true);
 
-	$ret = array(
+	if (!empty($profile[0]['about'])) {
+		$description = $profile[0]['about'];
+	} else {
+		$description = $uinfo[0]["about"];
+	}
+
+	if (!empty($usr[0]['default-location'])) {
+		$location = $usr[0]['default-location'];
+	} elseif (!empty($uinfo[0]["location"])) {
+		$location = $uinfo[0]["location"];
+	} else {
+		$location = $network_name;
+	}
+
+	$ret = [
 		'id' => intval($pcontact_id),
 		'id_str' => (string) intval($pcontact_id),
 		'name' => (($uinfo[0]['name']) ? $uinfo[0]['name'] : $uinfo[0]['nick']),
 		'screen_name' => (($uinfo[0]['nick']) ? $uinfo[0]['nick'] : $uinfo[0]['name']),
-		'location' => ($usr) ? $usr[0]['default-location'] : $network_name,
-		'description' => (($profile) ? $profile[0]['pdesc'] : null),
+		'location' => $location,
+		'description' => $description,
 		'profile_image_url' => $uinfo[0]['micro'],
 		'profile_image_url_https' => $uinfo[0]['micro'],
 		'url' => $uinfo[0]['url'],
@@ -778,11 +809,11 @@ function api_get_user(App $a, $contact_id = null)
 		'cid' => intval($uinfo[0]['cid']),
 		'self' => $uinfo[0]['self'],
 		'network' => $uinfo[0]['network'],
-	);
+	];
 
 	// If this is a local user and it uses Frio, we can get its color preferences.
 	if ($ret['self']) {
-		$theme_info = dba::select('user', ['theme'], ['uid' => $ret['uid']], ['limit' => 1]);
+		$theme_info = dba::selectFirst('user', ['theme'], ['uid' => $ret['uid']]);
 		if ($theme_info['theme'] === 'frio') {
 			$schema = PConfig::get($ret['uid'], 'frio', 'schema');
 			if ($schema && ($schema != '---')) {
@@ -837,7 +868,7 @@ function api_item_get_user(App $a, $item)
 		$owner_user = $status_user;
 	}
 
-	return (array($status_user, $owner_user));
+	return ([$status_user, $owner_user]);
 }
 
 /**
@@ -850,7 +881,7 @@ function api_item_get_user(App $a, $item)
  */
 function api_walk_recursive(array &$array, callable $callback)
 {
-	$new_array = array();
+	$new_array = [];
 
 	foreach ($array as $k => $v) {
 		if (is_array($v)) {
@@ -908,14 +939,14 @@ function api_create_xml($data, $root_element)
 	$data2 = array_pop($data);
 	$key = key($data2);
 
-	$namespaces = array("" => "http://api.twitter.com",
+	$namespaces = ["" => "http://api.twitter.com",
 				"statusnet" => "http://status.net/schema/api/1/",
 				"friendica" => "http://friendi.ca/schema/api/1/",
-				"georss" => "http://www.georss.org/georss");
+				"georss" => "http://www.georss.org/georss"];
 
 	/// @todo Auto detection of needed namespaces
-	if (in_array($root_element, array("ok", "hash", "config", "version", "ids", "notes", "photos"))) {
-		$namespaces = array();
+	if (in_array($root_element, ["ok", "hash", "config", "version", "ids", "notes", "photos"])) {
+		$namespaces = [];
 	}
 
 	if (is_array($data2)) {
@@ -923,7 +954,7 @@ function api_create_xml($data, $root_element)
 	}
 
 	if ($key == "0") {
-		$data4 = array();
+		$data4 = [];
 		$i = 1;
 
 		foreach ($data2 as $item) {
@@ -933,7 +964,7 @@ function api_create_xml($data, $root_element)
 		$data2 = $data4;
 	}
 
-	$data3 = array($root_element => $data2);
+	$data3 = [$root_element => $data2];
 
 	$ret = XML::fromArray($data3, $xml, false, $namespaces);
 	return $ret;
@@ -946,12 +977,10 @@ function api_create_xml($data, $root_element)
  * @param string $type         Return type (atom, rss, xml, json)
  * @param array  $data         JSON style array
  *
- * @return (string|object) XML data or JSON data
+ * @return (string|object|array) XML data or JSON data
  */
 function api_format_data($root_element, $type, $data)
 {
-	$a = get_app();
-
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -973,7 +1002,9 @@ function api_format_data($root_element, $type, $data)
 /**
  * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
  * returns a 401 status code and an error message if not.
- * http://developer.twitter.com/doc/get/account/verify_credentials
+ * @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials
+ *
+ * @param string $type Return type (atom, rss, xml, json)
  */
 function api_account_verify_credentials($type)
 {
@@ -1011,14 +1042,16 @@ function api_account_verify_credentials($type)
 	unset($user_info["uid"]);
 	unset($user_info["self"]);
 
-	return api_format_data("user", $type, array('user' => $user_info));
+	return api_format_data("user", $type, ['user' => $user_info]);
 }
 
-/// @TODO move to top of file or somwhere better
+/// @TODO move to top of file or somewhere better
 api_register_func('api/account/verify_credentials', 'api_account_verify_credentials', true);
 
 /**
  * Get data from $_POST or $_GET
+ *
+ * @param string $k
  */
 function requestdata($k)
 {
@@ -1031,7 +1064,13 @@ function requestdata($k)
 	return null;
 }
 
-/*Waitman Gobble Mod*/
+/**
+ * Waitman Gobble Mod
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return array|string
+ */
 function api_statuses_mediap($type)
 {
 	$a = get_app();
@@ -1056,7 +1095,7 @@ function api_statuses_mediap($type)
 		$purifier = new HTMLPurifier($config);
 		$txt = $purifier->purify($txt);
 	}
-	$txt = html2bbcode($txt);
+	$txt = HTML::toBBCode($txt);
 
 	$a->argv[1]=$user_info['screen_name']; //should be set to username?
 
@@ -1075,6 +1114,14 @@ function api_statuses_mediap($type)
 /// @TODO move this to top of file or somewhere better!
 api_register_func('api/statuses/mediap', 'api_statuses_mediap', true, API_METHOD_POST);
 
+/**
+ * Updates the user’s current status.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return array|string
+ * @see https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update
+ */
 function api_statuses_update($type)
 {
 
@@ -1085,12 +1132,9 @@ function api_statuses_update($type)
 		throw new ForbiddenException();
 	}
 
-	$user_info = api_get_user($a);
+	api_get_user($a);
 
 	// convert $_POST array items to the form we use for web posts.
-
-	// logger('api_post: ' . print_r($_POST,true));
-
 	if (requestdata('htmlstatus')) {
 		$txt = requestdata('htmlstatus');
 		if ((strpos($txt, '<') !== false) || (strpos($txt, '>') !== false)) {
@@ -1102,7 +1146,7 @@ function api_statuses_update($type)
 			$purifier = new HTMLPurifier($config);
 			$txt = $purifier->purify($txt);
 
-			$_REQUEST['body'] = html2bbcode($txt);
+			$_REQUEST['body'] = HTML::toBBCode($txt);
 		}
 	} else {
 		$_REQUEST['body'] = requestdata('status');
@@ -1134,7 +1178,7 @@ function api_statuses_update($type)
 		// Check for throttling (maximum posts per day, week and month)
 		$throttle_day = Config::get('system', 'throttle_limit_day');
 		if ($throttle_day > 0) {
-			$datefrom = date("Y-m-d H:i:s", time() - 24*60*60);
+			$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60);
 
 			$r = q(
 				"SELECT COUNT(*) AS `posts_day` FROM `item` WHERE `uid`=%d AND `wall`
@@ -1151,14 +1195,14 @@ function api_statuses_update($type)
 
 			if ($posts_day > $throttle_day) {
 				logger('Daily posting limit reached for user '.api_user(), LOGGER_DEBUG);
-				// die(api_error($type, sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day)));
-				throw new TooManyRequestsException(sprintf(t("Daily posting limit of %d posts reached. The post was rejected."), $throttle_day));
+				// die(api_error($type, L10n::t("Daily posting limit of %d posts reached. The post was rejected.", $throttle_day));
+				throw new TooManyRequestsException(L10n::tt("Daily posting limit of %d post reached. The post was rejected.", "Daily posting limit of %d posts reached. The post was rejected.", $throttle_day));
 			}
 		}
 
 		$throttle_week = Config::get('system', 'throttle_limit_week');
 		if ($throttle_week > 0) {
-			$datefrom = date("Y-m-d H:i:s", time() - 24*60*60*7);
+			$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*7);
 
 			$r = q(
 				"SELECT COUNT(*) AS `posts_week` FROM `item` WHERE `uid`=%d AND `wall`
@@ -1175,14 +1219,14 @@ function api_statuses_update($type)
 
 			if ($posts_week > $throttle_week) {
 				logger('Weekly posting limit reached for user '.api_user(), LOGGER_DEBUG);
-				// die(api_error($type, sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week)));
-				throw new TooManyRequestsException(sprintf(t("Weekly posting limit of %d posts reached. The post was rejected."), $throttle_week));
+				// die(api_error($type, L10n::t("Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week)));
+				throw new TooManyRequestsException(L10n::tt("Weekly posting limit of %d post reached. The post was rejected.", "Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week));
 			}
 		}
 
 		$throttle_month = Config::get('system', 'throttle_limit_month');
 		if ($throttle_month > 0) {
-			$datefrom = date("Y-m-d H:i:s", time() - 24*60*60*30);
+			$datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*30);
 
 			$r = q(
 				"SELECT COUNT(*) AS `posts_month` FROM `item` WHERE `uid`=%d AND `wall`
@@ -1199,8 +1243,8 @@ function api_statuses_update($type)
 
 			if ($posts_month > $throttle_month) {
 				logger('Monthly posting limit reached for user '.api_user(), LOGGER_DEBUG);
-				// die(api_error($type, sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month)));
-				throw new TooManyRequestsException(sprintf(t("Monthly posting limit of %d posts reached. The post was rejected."), $throttle_month));
+				// die(api_error($type, L10n::t("Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month));
+				throw new TooManyRequestsException(L10n::t("Monthly posting limit of %d post reached. The post was rejected.", "Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month));
 			}
 		}
 
@@ -1246,11 +1290,17 @@ function api_statuses_update($type)
 	return api_status_show($type);
 }
 
-/// @TODO move to top of file or somwhere better
+/// @TODO move to top of file or somewhere better
 api_register_func('api/statuses/update', 'api_statuses_update', true, API_METHOD_POST);
 api_register_func('api/statuses/update_with_media', 'api_statuses_update', true, API_METHOD_POST);
 
-function api_media_upload($type)
+/**
+ * Uploads an image to Friendica.
+ *
+ * @return array
+ * @see https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload
+ */
+function api_media_upload()
 {
 	$a = get_app();
 
@@ -1259,7 +1309,7 @@ function api_media_upload($type)
 		throw new ForbiddenException();
 	}
 
-	$user_info = api_get_user($a);
+	api_get_user($a);
 
 	if (!x($_FILES, 'media')) {
 		// Output error
@@ -1272,22 +1322,28 @@ function api_media_upload($type)
 		throw new InternalServerErrorException();
 	}
 
-	$returndata = array();
+	$returndata = [];
 	$returndata["media_id"] = $media["id"];
 	$returndata["media_id_string"] = (string)$media["id"];
 	$returndata["size"] = $media["size"];
-	$returndata["image"] = array("w" => $media["width"],
+	$returndata["image"] = ["w" => $media["width"],
 					"h" => $media["height"],
-					"image_type" => $media["type"]);
+					"image_type" => $media["type"]];
 
 	logger("Media uploaded: " . print_r($returndata, true), LOGGER_DEBUG);
 
-	return array("media" => $returndata);
+	return ["media" => $returndata];
 }
 
-/// @TODO move to top of file or somwhere better
+/// @TODO move to top of file or somewhere better
 api_register_func('api/media/upload', 'api_media_upload', true, API_METHOD_POST);
 
+/**
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return array|string
+ */
 function api_status_show($type)
 {
 	$a = get_app();
@@ -1332,7 +1388,7 @@ function api_status_show($type)
 			$geo = "geo";
 		}
 
-		$status_info = array(
+		$status_info = [
 			'created_at' => api_date($lastwall['created']),
 			'id' => intval($lastwall['id']),
 			'id_str' => (string) $lastwall['id'],
@@ -1359,7 +1415,7 @@ function api_status_show($type)
 			'statusnet_html' => $converted["html"],
 			'statusnet_conversation_id' => $lastwall['parent'],
 			'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'],
-		);
+		];
 
 		if (count($converted["attachments"]) > 0) {
 			$status_info["attachments"] = $converted["attachments"];
@@ -1370,9 +1426,9 @@ function api_status_show($type)
 		}
 
 		if (($lastwall['item_network'] != "") && ($status["source"] == 'web')) {
-			$status_info["source"] = network_to_name($lastwall['item_network'], $user_info['url']);
-		} elseif (($lastwall['item_network'] != "") && (network_to_name($lastwall['item_network'], $user_info['url']) != $status_info["source"])) {
-			$status_info["source"] = trim($status_info["source"].' ('.network_to_name($lastwall['item_network'], $user_info['url']).')');
+			$status_info["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']);
+		} elseif (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $status_info["source"])) {
+			$status_info["source"] = trim($status_info["source"].' ('.ContactSelector::networkToName($lastwall['item_network'], $user_info['url']).')');
 		}
 
 		// "uid" and "self" are only needed for some internal stuff, so remove it from here
@@ -1386,13 +1442,15 @@ function api_status_show($type)
 		return $status_info;
 	}
 
-	return api_format_data("statuses", $type, array('status' => $status_info));
+	return api_format_data("statuses", $type, ['status' => $status_info]);
 }
 
 /**
  * Returns extended information of a given user, specified by ID or screen name as per the required id parameter.
  * The author's most recent status will be returned inline.
- * http://developer.twitter.com/doc/get/users/show
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show
  */
 function api_users_show($type)
 {
@@ -1431,7 +1489,7 @@ function api_users_show($type)
 			$geo = "geo";
 		}
 
-		$user_info['status'] = array(
+		$user_info['status'] = [
 			'text' => $converted["text"],
 			'truncated' => false,
 			'created_at' => api_date($lastwall['created']),
@@ -1448,7 +1506,7 @@ function api_users_show($type)
 			'statusnet_html' => $converted["html"],
 			'statusnet_conversation_id' => $lastwall['parent'],
 			'external_url' => System::baseUrl() . "/display/" . $lastwall['guid'],
-		);
+		];
 
 		if (count($converted["attachments"]) > 0) {
 			$user_info["status"]["attachments"] = $converted["attachments"];
@@ -1459,11 +1517,11 @@ function api_users_show($type)
 		}
 
 		if (($lastwall['item_network'] != "") && ($user_info["status"]["source"] == 'web')) {
-			$user_info["status"]["source"] = network_to_name($lastwall['item_network'], $user_info['url']);
+			$user_info["status"]["source"] = ContactSelector::networkToName($lastwall['item_network'], $user_info['url']);
 		}
 
-		if (($lastwall['item_network'] != "") && (network_to_name($lastwall['item_network'], $user_info['url']) != $user_info["status"]["source"])) {
-			$user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . network_to_name($lastwall['item_network'], $user_info['url']) . ')');
+		if (($lastwall['item_network'] != "") && (ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) != $user_info["status"]["source"])) {
+			$user_info["status"]["source"] = trim($user_info["status"]["source"] . ' (' . ContactSelector::networkToName($lastwall['item_network'], $user_info['url']) . ')');
 		}
 	}
 
@@ -1471,20 +1529,26 @@ function api_users_show($type)
 	unset($user_info["uid"]);
 	unset($user_info["self"]);
 
-	return api_format_data("user", $type, array('user' => $user_info));
+	return api_format_data("user", $type, ['user' => $user_info]);
 }
 
 /// @TODO move to top of file or somewhere better
 api_register_func('api/users/show', 'api_users_show');
 api_register_func('api/externalprofile/show', 'api_users_show');
 
+/**
+ * Search a public user account.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return array|string
+ * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search
+ */
 function api_users_search($type)
 {
 	$a = get_app();
 
-	$page = (x($_REQUEST, 'page') ? $_REQUEST['page'] - 1 : 0);
-
-	$userlist = array();
+	$userlist = [];
 
 	if (x($_GET, 'q')) {
 		$r = q("SELECT id FROM `contact` WHERE `uid` = 0 AND `name` = '%s'", dbesc($_GET["q"]));
@@ -1496,7 +1560,7 @@ function api_users_search($type)
 		if (DBM::is_result($r)) {
 			$k = 0;
 			foreach ($r as $user) {
-				$user_info = api_get_user($a, $user["id"], "json");
+				$user_info = api_get_user($a, $user["id"]);
 
 				if ($type == "xml") {
 					$userlist[$k++.":user"] = $user_info;
@@ -1504,13 +1568,14 @@ function api_users_search($type)
 					$userlist[] = $user_info;
 				}
 			}
-			$userlist = array("users" => $userlist);
+			$userlist = ["users" => $userlist];
 		} else {
 			throw new BadRequestException("User not found.");
 		}
 	} else {
 		throw new BadRequestException("User not found.");
 	}
+
 	return api_format_data("users", $type, $userlist);
 }
 
@@ -1525,12 +1590,11 @@ api_register_func('api/users/search', 'api_users_search');
  * @param string $type Return format: json or xml
  *
  * @return array|string
- * @throws UnauthorizedException
- * @throws NotFoundException
+ * @throws NotFoundException if the results are empty.
  */
 function api_users_lookup($type)
 {
-	$users = array();
+	$users = [];
 
 	if (x($_REQUEST['user_id'])) {
 		foreach (explode(',', $_REQUEST['user_id']) as $id) {
@@ -1544,7 +1608,7 @@ function api_users_lookup($type)
 		throw new NotFoundException;
 	}
 
-	return api_format_data("users", $type, array('users' => $users));
+	return api_format_data("users", $type, ['users' => $users]);
 }
 
 /// @TODO move to top of file or somewhere better
@@ -1558,12 +1622,12 @@ api_register_func('api/users/lookup', 'api_users_lookup', true);
  * @param string $type Return format: json, xml, atom, rss
  *
  * @return array|string
- * @throws UnauthorizedException
- * @throws BadRequestException
+ * @throws BadRequestException if the "q" parameter is missing.
  */
 function api_search($type)
 {
-	$data = array();
+	$data = [];
+	$sql_extra = '';
 
 	if (!x($_REQUEST, 'q')) {
 		throw new BadRequestException("q parameter is required.");
@@ -1610,11 +1674,14 @@ api_register_func('api/search/tweets', 'api_search', true);
 api_register_func('api/search', 'api_search', true);
 
 /**
+ * Returns the most recent statuses posted by the user and the users they follow.
+ *
+ * @see https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline
  *
- * http://developer.twitter.com/doc/get/statuses/home_timeline
+ * @param string $type Return type (atom, rss, xml, json)
  *
- * TODO: Optional parameters
- * TODO: Add reply info
+ * @todo Optional parameters
+ * @todo Add reply info
  */
 function api_statuses_home_timeline($type)
 {
@@ -1681,7 +1748,7 @@ function api_statuses_home_timeline($type)
 	$ret = api_format_items($r, $user_info, false, $type);
 
 	// Set all posts from the query above to seen
-	$idarray = array();
+	$idarray = [];
 	foreach ($r as $item) {
 		$idarray[] = intval($item["id"]);
 	}
@@ -1692,11 +1759,11 @@ function api_statuses_home_timeline($type)
 		$unseen = q("SELECT `id` FROM `item` WHERE `unseen` AND `id` IN (%s)", $idlist);
 
 		if ($unseen) {
-			$r = q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist);
+			q("UPDATE `item` SET `unseen` = 0 WHERE `unseen` AND `id` IN (%s)", $idlist);
 		}
 	}
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -1711,6 +1778,13 @@ function api_statuses_home_timeline($type)
 api_register_func('api/statuses/home_timeline', 'api_statuses_home_timeline', true);
 api_register_func('api/statuses/friends_timeline', 'api_statuses_home_timeline', true);
 
+/**
+ * Returns the most recent statuses from public users.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return array|string
+ */
 function api_statuses_public_timeline($type)
 {
 	$a = get_app();
@@ -1735,13 +1809,15 @@ function api_statuses_public_timeline($type)
 	$conversation_id = (x($_REQUEST, 'conversation_id') ? $_REQUEST['conversation_id'] : 0);
 
 	$start = $page * $count;
+	$sql_extra = '';
 
 	if ($exclude_replies && !$conversation_id) {
 		if ($max_id > 0) {
 			$sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id);
 		}
 
-		$r = dba::p("SELECT " . item_fieldlists() . "
+		$r = dba::p(
+			"SELECT " . item_fieldlists() . "
 			FROM `thread`
 			STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
 			" . item_joins() . "
@@ -1770,7 +1846,8 @@ function api_statuses_public_timeline($type)
 			$sql_extra .= ' AND `item`.`parent` = ' . intval($conversation_id);
 		}
 
-		$r = dba::p("SELECT " . item_fieldlists() . "
+		$r = dba::p(
+			"SELECT " . item_fieldlists() . "
 			FROM `item`
 			" . item_joins() . "
 			STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid`
@@ -1794,7 +1871,7 @@ function api_statuses_public_timeline($type)
 
 	$ret = api_format_items($r, $user_info, false, $type);
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -1809,6 +1886,8 @@ function api_statuses_public_timeline($type)
 api_register_func('api/statuses/public_timeline', 'api_statuses_public_timeline', true);
 
 /**
+ * Returns the most recent statuses posted by users this node knows about.
+ *
  * @brief Returns the list of public federated posts this node knows about
  *
  * @param string $type Return format: json, xml, atom, rss
@@ -1841,7 +1920,8 @@ function api_statuses_networkpublic_timeline($type)
 		$sql_extra = 'AND `thread`.`iid` <= ' . intval($max_id);
 	}
 
-	$r = dba::p("SELECT " . item_fieldlists() . "
+	$r = dba::p(
+		"SELECT " . item_fieldlists() . "
 		FROM `thread`
 		STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
 		" . item_joins() . "
@@ -1863,7 +1943,7 @@ function api_statuses_networkpublic_timeline($type)
 
 	$ret = api_format_items($r, $user_info, false, $type);
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -1878,7 +1958,11 @@ function api_statuses_networkpublic_timeline($type)
 api_register_func('api/statuses/networkpublic_timeline', 'api_statuses_networkpublic_timeline', true);
 
 /**
- * @TODO nothing to say?
+ * Returns a single status.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @see https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id
  */
 function api_statuses_show($type)
 {
@@ -1937,10 +2021,10 @@ function api_statuses_show($type)
 	$ret = api_format_items($r, $user_info, false, $type);
 
 	if ($conversation) {
-		$data = array('status' => $ret);
+		$data = ['status' => $ret];
 		return api_format_data("statuses", $type, $data);
 	} else {
-		$data = array('status' => $ret[0]);
+		$data = ['status' => $ret[0]];
 		return api_format_data("status", $type, $data);
 	}
 }
@@ -1949,7 +2033,10 @@ function api_statuses_show($type)
 api_register_func('api/statuses/show', 'api_statuses_show', true);
 
 /**
- * @TODO nothing to say?
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @todo nothing to say?
  */
 function api_conversation_show($type)
 {
@@ -2013,10 +2100,12 @@ function api_conversation_show($type)
 		AND `item`.`uid` = %d AND `item`.`verb` = '%s'
 		AND `item`.`id`>%d $sql_extra
 		ORDER BY `item`.`id` DESC LIMIT %d ,%d",
-		intval($id), intval(api_user()),
+		intval($id),
+		intval(api_user()),
 		dbesc(ACTIVITY_POST),
 		intval($since_id),
-		intval($start), intval($count)
+		intval($start),
+		intval($count)
 	);
 
 	if (!DBM::is_result($r)) {
@@ -2025,7 +2114,7 @@ function api_conversation_show($type)
 
 	$ret = api_format_items($r, $user_info, false, $type);
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	return api_format_data("statuses", $type, $data);
 }
 
@@ -2034,7 +2123,11 @@ api_register_func('api/conversation/show', 'api_conversation_show', true);
 api_register_func('api/statusnet/conversation', 'api_conversation_show', true);
 
 /**
- * @TODO nothing to say?
+ * Repeats a status.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @see https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id
  */
 function api_statuses_repeat($type)
 {
@@ -2046,7 +2139,7 @@ function api_statuses_repeat($type)
 		throw new ForbiddenException();
 	}
 
-	$user_info = api_get_user($a);
+	api_get_user($a);
 
 	// params
 	$id = intval($a->argv[3]);
@@ -2073,7 +2166,6 @@ function api_statuses_repeat($type)
 		WHERE `item`.`visible` AND NOT `item`.`moderated` AND NOT `item`.`deleted`
 		AND NOT `item`.`private` AND `item`.`allow_cid` = '' AND `item`.`allow_gid` = ''
 		AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = ''
-		$sql_extra
 		AND `item`.`id`=%d",
 		intval($id)
 	);
@@ -2112,7 +2204,11 @@ function api_statuses_repeat($type)
 api_register_func('api/statuses/retweet', 'api_statuses_repeat', true, API_METHOD_POST);
 
 /**
- * @TODO nothing to say?
+ * Destroys a specific status.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @see https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-destroy-id
  */
 function api_statuses_destroy($type)
 {
@@ -2122,7 +2218,7 @@ function api_statuses_destroy($type)
 		throw new ForbiddenException();
 	}
 
-	$user_info = api_get_user($a);
+	api_get_user($a);
 
 	// params
 	$id = intval($a->argv[3]);
@@ -2140,7 +2236,7 @@ function api_statuses_destroy($type)
 
 	$ret = api_statuses_show($type);
 
-	drop_item($id, false);
+	Item::deleteById($id);
 
 	return $ret;
 }
@@ -2149,8 +2245,11 @@ function api_statuses_destroy($type)
 api_register_func('api/statuses/destroy', 'api_statuses_destroy', true, API_METHOD_DELETE);
 
 /**
- * @TODO Nothing more than an URL to say?
- * http://developer.twitter.com/doc/get/statuses/mentions
+ * Returns the most recent mentions.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @see http://developer.twitter.com/doc/get/statuses/mentions
  */
 function api_statuses_mentions($type)
 {
@@ -2171,26 +2270,25 @@ function api_statuses_mentions($type)
 
 
 	// params
-	$count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 20);
-	$page = (x($_REQUEST, 'page') ? $_REQUEST['page'] -1 : 0);
-	if ($page < 0) {
-		$page = 0;
+	$since_id = defaults($_REQUEST, 'since_id', 0);
+	$max_id   = defaults($_REQUEST, 'max_id'  , 0);
+	$count    = defaults($_REQUEST, 'count'   , 20);
+	$page     = defaults($_REQUEST, 'page'    , 1);
+	if ($page < 1) {
+		$page = 1;
 	}
-	$since_id = (x($_REQUEST, 'since_id') ? $_REQUEST['since_id'] : 0);
-	$max_id = (x($_REQUEST, 'max_id') ? $_REQUEST['max_id'] : 0);
-	//$since_id = 0;//$since_id = (x($_REQUEST, 'since_id')?$_REQUEST['since_id'] : 0);
 
-	$start = $page * $count;
+	$start = ($page - 1) * $count;
 
 	// Ugly code - should be changed
 	$myurl = System::baseUrl() . '/profile/'. $a->user['nickname'];
 	$myurl = substr($myurl, strpos($myurl, '://') + 3);
-	//$myurl = str_replace(array('www.','.'),array('','\\.'),$myurl);
 	$myurl = str_replace('www.', '', $myurl);
-	$diasp_url = str_replace('/profile/', '/u/', $myurl);
+
+	$sql_extra = '';
 
 	if ($max_id > 0) {
-		$sql_extra = ' AND `item`.`id` <= ' . intval($max_id);
+		$sql_extra .= ' AND `item`.`id` <= ' . intval($max_id);
 	}
 
 	$r = q(
@@ -2220,7 +2318,7 @@ function api_statuses_mentions($type)
 
 	$ret = api_format_items($r, $user_info, false, $type);
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -2236,11 +2334,14 @@ api_register_func('api/statuses/mentions', 'api_statuses_mentions', true);
 api_register_func('api/statuses/replies', 'api_statuses_mentions', true);
 
 /**
+ * Returns the most recent statuses posted by the user.
+ *
  * @brief Returns a user's public timeline
  *
  * @param string $type Either "json" or "xml"
  * @return string|array
  * @throws ForbiddenException
+ * @see https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline
  */
 function api_statuses_user_timeline($type)
 {
@@ -2313,7 +2414,7 @@ function api_statuses_user_timeline($type)
 
 	$ret = api_format_items($r, $user_info, true, $type);
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -2324,14 +2425,16 @@ function api_statuses_user_timeline($type)
 	return api_format_data("statuses", $type, $data);
 }
 
-/// @TODO move to top of file or somwhere better
-api_register_func('api/statuses/user_timeline','api_statuses_user_timeline', true);
+/// @TODO move to top of file or somewhere better
+api_register_func('api/statuses/user_timeline', 'api_statuses_user_timeline', true);
 
 /**
- * Star/unstar an item
+ * Star/unstar an item.
  * param: id : id of the item
  *
- * api v1 : https://web.archive.org/web/20131019055350/https://dev.twitter.com/docs/api/1/post/favorites/create/%3Aid
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @see https://web.archive.org/web/20131019055350/https://dev.twitter.com/docs/api/1/post/favorites/create/%3Aid
  */
 function api_favorites_create_destroy($type)
 {
@@ -2376,9 +2479,7 @@ function api_favorites_create_destroy($type)
 			throw new BadRequestException("Invalid action ".$action);
 	}
 
-	$r = q("UPDATE item SET starred=%d WHERE id=%d AND uid=%d",	$item[0]['starred'], $itemid, api_user());
-
-	q("UPDATE thread SET starred=%d WHERE iid=%d AND uid=%d", $item[0]['starred'], $itemid, api_user());
+	$r = Item::update(['starred' => $item[0]['starred']], ['id' => $itemid]);
 
 	if ($r === false) {
 		throw new InternalServerErrorException("DB error");
@@ -2389,7 +2490,7 @@ function api_favorites_create_destroy($type)
 	$rets = api_format_items($item, $user_info, false, $type);
 	$ret = $rets[0];
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -2399,10 +2500,17 @@ function api_favorites_create_destroy($type)
 	return api_format_data("status", $type, $data);
 }
 
-/// @TODO move to top of file or somwhere better
+/// @TODO move to top of file or somewhere better
 api_register_func('api/favorites/create', 'api_favorites_create_destroy', true, API_METHOD_POST);
 api_register_func('api/favorites/destroy', 'api_favorites_create_destroy', true, API_METHOD_DELETE);
 
+/**
+ * Returns the most recent favorite statuses.
+ *
+ * @param string $type Return type (atom, rss, xml, json)
+ *
+ * @return string|array
+ */
 function api_favorites($type)
 {
 	global $called_api;
@@ -2413,7 +2521,7 @@ function api_favorites($type)
 		throw new ForbiddenException();
 	}
 
-	$called_api = array();
+	$called_api = [];
 
 	$user_info = api_get_user($a);
 
@@ -2422,7 +2530,7 @@ function api_favorites($type)
 	logger('api_favorites: self:' . $user_info['self']);
 
 	if ($user_info['self'] == 0) {
-		$ret = array();
+		$ret = [];
 	} else {
 		$sql_extra = "";
 
@@ -2464,7 +2572,7 @@ function api_favorites($type)
 		$ret = api_format_items($r, $user_info, false, $type);
 	}
 
-	$data = array('status' => $ret);
+	$data = ['status' => $ret];
 	switch ($type) {
 		case "atom":
 		case "rss":
@@ -2474,13 +2582,21 @@ function api_favorites($type)
 	return api_format_data("statuses", $type, $data);
 }
 
-/// @TODO move to top of file or somwhere better
+/// @TODO move to top of file or somewhere better
 api_register_func('api/favorites', 'api_favorites', true);
 
+/**
+ *
+ * @param array $item
+ * @param array $recipient
+ * @param array $sender
+ *
+ * @return array
+ */
 function api_format_messages($item, $recipient, $sender)
 {
 	// standard meta information
-	$ret = array(
+	$ret = [
 			'id'                    => $item['id'],
 			'sender_id'             => $sender['id'] ,
 			'text'                  => "",
@@ -2493,7 +2609,7 @@ function api_format_messages($item, $recipient, $sender)
 			'title'                 => "",
 			'friendica_seen'        => $item['seen'],
 			'friendica_parent_uri'  => $item['parent-uri'],
-	);
+	];
 
 	// "uid" and "self" are only needed for some internal stuff, so remove it from here
 	unset($ret["sender"]["uid"]);
@@ -2505,13 +2621,12 @@ function api_format_messages($item, $recipient, $sender)
 	if (x($_GET, 'getText')) {
 		$ret['title'] = $item['title'];
 		if ($_GET['getText'] == 'html') {
-			$ret['text'] = bbcode($item['body'], false, false);
+			$ret['text'] = BBCode::convert($item['body'], false);
 		} elseif ($_GET['getText'] == 'plain') {
-			//$ret['text'] = html2plain(bbcode($item['body'], false, false, true), 0);
-			$ret['text'] = trim(html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 2, true), 0));
+			$ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0));
 		}
 	} else {
-		$ret['text'] = $item['title'] . "\n" . html2plain(bbcode(api_clean_plain_items($item['body']), false, false, 2, true), 0);
+		$ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0);
 	}
 	if (x($_GET, 'getUserObjects') && $_GET['getUserObjects'] == 'false') {
 		unset($ret['sender']);
@@ -2521,14 +2636,20 @@ function api_format_messages($item, $recipient, $sender)
 	return $ret;
 }
 
+/**
+ *
+ * @param array $item
+ *
+ * @return array
+ */
 function api_convert_item($item)
 {
 	$body = $item['body'];
 	$attachments = api_get_attachments($body);
 
 	// Workaround for ostatus messages where the title is identically to the body
-	$html = bbcode(api_clean_plain_items($body), false, false, 2, true);
-	$statusbody = trim(html2plain($html, 0));
+	$html = BBCode::convert(api_clean_plain_items($body), false, 2, true);
+	$statusbody = trim(HTML::toPlaintext($html, 0));
 
 	// handle data: images
 	$statusbody = api_format_items_embeded_images($item, $statusbody);
@@ -2545,21 +2666,21 @@ function api_convert_item($item)
 		$statustext = substr($statustext, 0, 1000)."... \n".$item["plink"];
 	}
 
-	$statushtml = trim(bbcode($body, false, false));
+	$statushtml = BBCode::convert(api_clean_attachments($body), false);
 
 	// Workaround for clients with limited HTML parser functionality
-	$search = array("
", "
", "
", + $search = ["
", "
", "
", "

", "

", "

", "

", "

", "

", "

", "

", - "
", "
", "
", "
"); - $replace = array("
", "
", "

", + "
", "
", "
", "
"]; + $replace = ["
", "
", "

", "

", "


", "

", "


", "

", "


", "

", "


", - "
", "

", "
", "

"); + "
", "

", "
", "

"]; $statushtml = str_replace($search, $replace, $statushtml); if ($item['title'] != "") { - $statushtml = "

" . bbcode($item['title']) . "


" . $statushtml; + $statushtml = "

" . BBCode::convert($item['title']) . "


" . $statushtml; } do { @@ -2577,19 +2698,25 @@ function api_convert_item($item) // feeds without body should contain the link if (($item['network'] == NETWORK_FEED) && (strlen($item['body']) == 0)) { - $statushtml .= bbcode($item['plink']); + $statushtml .= BBCode::convert($item['plink']); } $entities = api_get_entitities($statustext, $body); - return array( + return [ "text" => $statustext, "html" => $statushtml, "attachments" => $attachments, "entities" => $entities - ); + ]; } +/** + * + * @param string $body + * + * @return array|false + */ function api_get_attachments(&$body) { $text = $body; @@ -2602,13 +2729,13 @@ function api_get_attachments(&$body) return false; } - $attachments = array(); + $attachments = []; foreach ($images[1] as $image) { $imagedata = Image::getInfoFromURL($image); if ($imagedata) { - $attachments[] = array("url" => $image, "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]); + $attachments[] = ["url" => $image, "mimetype" => $imagedata["mime"], "size" => $imagedata["size"]]; } } @@ -2621,15 +2748,16 @@ function api_get_attachments(&$body) return $attachments; } +/** + * + * @param string $text + * @param string $bbcode + * + * @return array + * @todo Links at the first character of the post + */ function api_get_entitities(&$text, $bbcode) { - /* - To-Do: - * Links at the first character of the post - */ - - $a = get_app(); - $include_entities = strtolower(x($_REQUEST, 'include_entities') ? $_REQUEST['include_entities'] : "false"); if ($include_entities != "true") { @@ -2639,19 +2767,19 @@ function api_get_entitities(&$text, $bbcode) $replace = proxy_url($image); $text = str_replace($image, $replace, $text); } - return array(); + return []; } - $bbcode = bb_CleanPictureLinks($bbcode); + $bbcode = BBCode::cleanPictureLinks($bbcode); // Change pure links in text to bbcode uris $bbcode = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2]$2[/url]', $bbcode); - $entities = array(); - $entities["hashtags"] = array(); - $entities["symbols"] = array(); - $entities["urls"] = array(); - $entities["user_mentions"] = array(); + $entities = []; + $entities["hashtags"] = []; + $entities["symbols"] = []; + $entities["urls"] = []; + $entities["user_mentions"] = []; $URLSearchString = "^\[\]"; @@ -2680,12 +2808,12 @@ function api_get_entitities(&$text, $bbcode) //preg_match_all("/\[url\]([$URLSearchString]*)\[\/url\]/ism", $bbcode, $urls1); preg_match_all("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $bbcode, $urls); - $ordered_urls = array(); + $ordered_urls = []; foreach ($urls[1] as $id => $url) { //$start = strpos($text, $url, $offset); $start = iconv_strpos($text, $url, 0, "UTF-8"); if (!($start === false)) { - $ordered_urls[$start] = array("url" => $url, "title" => $urls[2][$id]); + $ordered_urls[$start] = ["url" => $url, "title" => $urls[2][$id]]; } } @@ -2696,44 +2824,47 @@ function api_get_entitities(&$text, $bbcode) foreach ($ordered_urls as $url) { if ((substr($url["title"], 0, 7) != "http://") && (substr($url["title"], 0, 8) != "https://") && !strpos($url["title"], "http://") && !strpos($url["title"], "https://") - ) + ) { $display_url = $url["title"]; - else { - $display_url = str_replace(array("http://www.", "https://www."), array("", ""), $url["url"]); - $display_url = str_replace(array("http://", "https://"), array("", ""), $display_url); + } else { + $display_url = str_replace(["http://www.", "https://www."], ["", ""], $url["url"]); + $display_url = str_replace(["http://", "https://"], ["", ""], $display_url); - if (strlen($display_url) > 26) + if (strlen($display_url) > 26) { $display_url = substr($display_url, 0, 25)."…"; + } } //$start = strpos($text, $url, $offset); $start = iconv_strpos($text, $url["url"], $offset, "UTF-8"); if (!($start === false)) { - $entities["urls"][] = array("url" => $url["url"], + $entities["urls"][] = ["url" => $url["url"], "expanded_url" => $url["url"], "display_url" => $display_url, - "indices" => array($start, $start+strlen($url["url"]))); + "indices" => [$start, $start+strlen($url["url"])]]; $offset = $start + 1; } } preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images); - $ordered_images = array(); + $ordered_images = []; foreach ($images[1] as $image) { //$start = strpos($text, $url, $offset); $start = iconv_strpos($text, $image, 0, "UTF-8"); - if (!($start === false)) + if (!($start === false)) { $ordered_images[$start] = $image; + } } //$entities["media"] = array(); $offset = 0; foreach ($ordered_images as $url) { - $display_url = str_replace(array("http://www.", "https://www."), array("", ""), $url); - $display_url = str_replace(array("http://", "https://"), array("", ""), $display_url); + $display_url = str_replace(["http://www.", "https://www."], ["", ""], $url); + $display_url = str_replace(["http://", "https://"], ["", ""], $display_url); - if (strlen($display_url) > 26) + if (strlen($display_url) > 26) { $display_url = substr($display_url, 0, 25)."…"; + } $start = iconv_strpos($text, $url, $offset, "UTF-8"); if (!($start === false)) { @@ -2744,38 +2875,38 @@ function api_get_entitities(&$text, $bbcode) if (!Config::get("system", "proxy_disabled")) { $media_url = proxy_url($url); - $sizes = array(); + $sizes = []; $scale = Image::getScalingDimensions($image[0], $image[1], 150); - $sizes["thumb"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"); + $sizes["thumb"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"]; if (($image[0] > 150) || ($image[1] > 150)) { $scale = Image::getScalingDimensions($image[0], $image[1], 340); - $sizes["small"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"); + $sizes["small"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"]; } $scale = Image::getScalingDimensions($image[0], $image[1], 600); - $sizes["medium"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"); + $sizes["medium"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"]; if (($image[0] > 600) || ($image[1] > 600)) { $scale = Image::getScalingDimensions($image[0], $image[1], 1024); - $sizes["large"] = array("w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"); + $sizes["large"] = ["w" => $scale["width"], "h" => $scale["height"], "resize" => "fit"]; } } else { $media_url = $url; - $sizes["medium"] = array("w" => $image[0], "h" => $image[1], "resize" => "fit"); + $sizes["medium"] = ["w" => $image[0], "h" => $image[1], "resize" => "fit"]; } - $entities["media"][] = array( + $entities["media"][] = [ "id" => $start+1, "id_str" => (string)$start+1, - "indices" => array($start, $start+strlen($url)), + "indices" => [$start, $start+strlen($url)], "media_url" => normalise_link($media_url), "media_url_https" => $media_url, "url" => $url, "display_url" => $display_url, "expanded_url" => $url, "type" => "photo", - "sizes" => $sizes); + "sizes" => $sizes]; } $offset = $start + 1; } @@ -2783,41 +2914,48 @@ function api_get_entitities(&$text, $bbcode) return $entities; } -function api_format_items_embeded_images(&$item, $text) + +/** + * + * @param array $item + * @param string $text + * + * @return string + */ +function api_format_items_embeded_images($item, $text) { $text = preg_replace_callback( - "|data:image/([^;]+)[^=]+=*|m", - function ($match) use ($item) { - return System::baseUrl()."/display/".$item['guid']; + '|data:image/([^;]+)[^=]+=*|m', + function () use ($item) { + return System::baseUrl() . '/display/' . $item['guid']; }, $text ); return $text; } - /** * @brief return name as array * * @param string $txt text * @return array - * name => 'name' + * 'name' => 'name', * 'url => 'url' */ function api_contactlink_to_array($txt) { - $match = array(); + $match = []; $r = preg_match_all('|([^<]*)|', $txt, $match); if ($r && count($match)==3) { - $res = array( + $res = [ 'name' => $match[2], 'url' => $match[1] - ); + ]; } else { - $res = array( - 'name' => $text, + $res = [ + 'name' => $txt, 'url' => "" - ); + ]; } return $res; } @@ -2827,21 +2965,23 @@ function api_contactlink_to_array($txt) * @brief return likes, dislikes and attend status for item * * @param array $item array + * @param string $type Return type (atom, rss, xml, json) + * * @return array - * likes => int count + * likes => int count, * dislikes => int count */ function api_format_items_activities(&$item, $type = "json") { $a = get_app(); - $activities = array( - 'like' => array(), - 'dislike' => array(), - 'attendyes' => array(), - 'attendno' => array(), - 'attendmaybe' => array(), - ); + $activities = [ + 'like' => [], + 'dislike' => [], + 'attendyes' => [], + 'attendno' => [], + 'attendmaybe' => [], + ]; $items = q( 'SELECT * FROM item @@ -2878,14 +3018,15 @@ function api_format_items_activities(&$item, $type = "json") } if ($type == "xml") { - $xml_activities = array(); + $xml_activities = []; foreach ($activities as $k => $v) { // change xml element from "like" to "friendica:like" $xml_activities["friendica:".$k] = $v; // add user data into xml output $k_user = 0; - foreach ($v as $user) + foreach ($v as $user) { $xml_activities["friendica:".$k][$k_user++.":user"] = $user; + } } $activities = $xml_activities; } @@ -2897,68 +3038,68 @@ function api_format_items_activities(&$item, $type = "json") /** * @brief return data from profiles * - * @param array $profile array containing data from db table 'profile' - * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' + * @param array $profile_row array containing data from db table 'profile' * @return array */ -function api_format_items_profiles(&$profile = null, $type = "json") +function api_format_items_profiles($profile_row) { - if ($profile != null) { - $profile = array('profile_id' => $profile['id'], - 'profile_name' => $profile['profile-name'], - 'is_default' => $profile['is-default'] ? true : false, - 'hide_friends'=> $profile['hide-friends'] ? true : false, - 'profile_photo' => $profile['photo'], - 'profile_thumb' => $profile['thumb'], - 'publish' => $profile['publish'] ? true : false, - 'net_publish' => $profile['net-publish'] ? true : false, - 'description' => $profile['pdesc'], - 'date_of_birth' => $profile['dob'], - 'address' => $profile['address'], - 'city' => $profile['locality'], - 'region' => $profile['region'], - 'postal_code' => $profile['postal-code'], - 'country' => $profile['country-name'], - 'hometown' => $profile['hometown'], - 'gender' => $profile['gender'], - 'marital' => $profile['marital'], - 'marital_with' => $profile['with'], - 'marital_since' => $profile['howlong'], - 'sexual' => $profile['sexual'], - 'politic' => $profile['politic'], - 'religion' => $profile['religion'], - 'public_keywords' => $profile['pub_keywords'], - 'private_keywords' => $profile['prv_keywords'], - 'likes' => bbcode(api_clean_plain_items($profile['likes']), false, false, 2, false), - 'dislikes' => bbcode(api_clean_plain_items($profile['dislikes']), false, false, 2, false), - 'about' => bbcode(api_clean_plain_items($profile['about']), false, false, 2, false), - 'music' => bbcode(api_clean_plain_items($profile['music']), false, false, 2, false), - 'book' => bbcode(api_clean_plain_items($profile['book']), false, false, 2, false), - 'tv' => bbcode(api_clean_plain_items($profile['tv']), false, false, 2, false), - 'film' => bbcode(api_clean_plain_items($profile['film']), false, false, 2, false), - 'interest' => bbcode(api_clean_plain_items($profile['interest']), false, false, 2, false), - 'romance' => bbcode(api_clean_plain_items($profile['romance']), false, false, 2, false), - 'work' => bbcode(api_clean_plain_items($profile['work']), false, false, 2, false), - 'education' => bbcode(api_clean_plain_items($profile['education']), false, false, 2, false), - 'social_networks' => bbcode(api_clean_plain_items($profile['contact']), false, false, 2, false), - 'homepage' => $profile['homepage'], - 'users' => null); - return $profile; - } + $profile = [ + 'profile_id' => $profile_row['id'], + 'profile_name' => $profile_row['profile-name'], + 'is_default' => $profile_row['is-default'] ? true : false, + 'hide_friends' => $profile_row['hide-friends'] ? true : false, + 'profile_photo' => $profile_row['photo'], + 'profile_thumb' => $profile_row['thumb'], + 'publish' => $profile_row['publish'] ? true : false, + 'net_publish' => $profile_row['net-publish'] ? true : false, + 'description' => $profile_row['pdesc'], + 'date_of_birth' => $profile_row['dob'], + 'address' => $profile_row['address'], + 'city' => $profile_row['locality'], + 'region' => $profile_row['region'], + 'postal_code' => $profile_row['postal-code'], + 'country' => $profile_row['country-name'], + 'hometown' => $profile_row['hometown'], + 'gender' => $profile_row['gender'], + 'marital' => $profile_row['marital'], + 'marital_with' => $profile_row['with'], + 'marital_since' => $profile_row['howlong'], + 'sexual' => $profile_row['sexual'], + 'politic' => $profile_row['politic'], + 'religion' => $profile_row['religion'], + 'public_keywords' => $profile_row['pub_keywords'], + 'private_keywords' => $profile_row['prv_keywords'], + 'likes' => BBCode::convert(api_clean_plain_items($profile_row['likes']) , false, 2), + 'dislikes' => BBCode::convert(api_clean_plain_items($profile_row['dislikes']) , false, 2), + 'about' => BBCode::convert(api_clean_plain_items($profile_row['about']) , false, 2), + 'music' => BBCode::convert(api_clean_plain_items($profile_row['music']) , false, 2), + 'book' => BBCode::convert(api_clean_plain_items($profile_row['book']) , false, 2), + 'tv' => BBCode::convert(api_clean_plain_items($profile_row['tv']) , false, 2), + 'film' => BBCode::convert(api_clean_plain_items($profile_row['film']) , false, 2), + 'interest' => BBCode::convert(api_clean_plain_items($profile_row['interest']) , false, 2), + 'romance' => BBCode::convert(api_clean_plain_items($profile_row['romance']) , false, 2), + 'work' => BBCode::convert(api_clean_plain_items($profile_row['work']) , false, 2), + 'education' => BBCode::convert(api_clean_plain_items($profile_row['education']), false, 2), + 'social_networks' => BBCode::convert(api_clean_plain_items($profile_row['contact']) , false, 2), + 'homepage' => $profile_row['homepage'], + 'users' => null + ]; + return $profile; } /** * @brief format items to be returned by api * - * @param array $r array of items - * @param array $user_info - * @param bool $filter_user filter items by $user_info + * @param array $r array of items + * @param array $user_info + * @param bool $filter_user filter items by $user_info + * @param string $type Return type (atom, rss, xml, json) */ function api_format_items($r, $user_info, $filter_user = false, $type = "json") { $a = get_app(); - $ret = array(); + $ret = []; foreach ($r as $item) { localize_item($item); @@ -2979,7 +3120,7 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") $geo = "geo"; } - $status = array( + $status = [ 'text' => $converted["text"], 'truncated' => false, 'created_at'=> api_date($item['created']), @@ -3000,7 +3141,7 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") 'statusnet_conversation_id' => $item['parent'], 'external_url' => System::baseUrl() . "/display/" . $item['guid'], 'friendica_activities' => api_format_items_activities($item, $type), - ); + ]; if (count($converted["attachments"]) > 0) { $status["attachments"] = $converted["attachments"]; @@ -3011,9 +3152,9 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") } if (($item['item_network'] != "") && ($status["source"] == 'web')) { - $status["source"] = network_to_name($item['item_network'], $user_info['url']); - } elseif (($item['item_network'] != "") && (network_to_name($item['item_network'], $user_info['url']) != $status["source"])) { - $status["source"] = trim($status["source"].' ('.network_to_name($item['item_network'], $user_info['url']).')'); + $status["source"] = ContactSelector::networkToName($item['item_network'], $user_info['url']); + } elseif (($item['item_network'] != "") && (ContactSelector::networkToName($item['item_network'], $user_info['url']) != $status["source"])) { + $status["source"] = trim($status["source"].' ('.ContactSelector::networkToName($item['item_network'], $user_info['url']).')'); } @@ -3033,7 +3174,7 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") } catch (BadRequestException $e) { // user not found. should be found? /// @todo check if the user should be always found - $retweeted_status["user"] = array(); + $retweeted_status["user"] = []; } $rt_converted = api_convert_item($retweeted_item); @@ -3053,12 +3194,13 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") if ($item["coord"] != "") { $coords = explode(' ', $item["coord"]); if (count($coords) == 2) { - if ($type == "json") - $status["geo"] = array('type' => 'Point', - 'coordinates' => array((float) $coords[0], - (float) $coords[1])); - else // Not sure if this is the official format - if someone founds a documentation we can check + if ($type == "json") { + $status["geo"] = ['type' => 'Point', + 'coordinates' => [(float) $coords[0], + (float) $coords[1]]]; + } else {// Not sure if this is the official format - if someone founds a documentation we can check $status["georss:point"] = $item["coord"]; + } } } $ret[] = $status; @@ -3066,34 +3208,48 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json") return $ret; } +/** + * Returns the remaining number of API requests available to the user before the API limit is reached. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_account_rate_limit_status($type) { if ($type == "xml") { - $hash = array( + $hash = [ 'remaining-hits' => '150', - '@attributes' => array("type" => "integer"), + '@attributes' => ["type" => "integer"], 'hourly-limit' => '150', - '@attributes2' => array("type" => "integer"), - 'reset-time' => datetime_convert('UTC', 'UTC', 'now + 1 hour', ATOM_TIME), - '@attributes3' => array("type" => "datetime"), + '@attributes2' => ["type" => "integer"], + 'reset-time' => DateTimeFormat::utc('now + 1 hour', DateTimeFormat::ATOM), + '@attributes3' => ["type" => "datetime"], 'reset_time_in_seconds' => strtotime('now + 1 hour'), - '@attributes4' => array("type" => "integer"), - ); + '@attributes4' => ["type" => "integer"], + ]; } else { - $hash = array( + $hash = [ 'reset_time_in_seconds' => strtotime('now + 1 hour'), 'remaining_hits' => '150', 'hourly_limit' => '150', - 'reset_time' => api_date(datetime_convert('UTC', 'UTC', 'now + 1 hour', ATOM_TIME)), - ); + 'reset_time' => api_date(DateTimeFormat::utc('now + 1 hour', DateTimeFormat::ATOM)), + ]; } - return api_format_data('hash', $type, array('hash' => $hash)); + return api_format_data('hash', $type, ['hash' => $hash]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/account/rate_limit_status', 'api_account_rate_limit_status', true); +/** + * Returns the string "ok" in the requested format with a 200 OK HTTP status code. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_help_test($type) { if ($type == 'xml') { @@ -3102,38 +3258,52 @@ function api_help_test($type) $ok = "ok"; } - return api_format_data('ok', $type, array("ok" => $ok)); + return api_format_data('ok', $type, ["ok" => $ok]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/help/test', 'api_help_test', false); +/** + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_lists($type) { - $ret = array(); + $ret = []; /// @TODO $ret is not filled here? - return api_format_data('lists', $type, array("lists_list" => $ret)); + return api_format_data('lists', $type, ["lists_list" => $ret]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/lists', 'api_lists', true); +/** + * Returns all lists the user subscribes to. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list + */ function api_lists_list($type) { - $ret = array(); + $ret = []; /// @TODO $ret is not filled here? - return api_format_data('lists', $type, array("lists_list" => $ret)); + return api_format_data('lists', $type, ["lists_list" => $ret]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/lists/list', 'api_lists_list', true); /** - * @brief Returns either the friends of the follower list - * - * Note: Considers friends and followers lists to be private and won't return + * Considers friends and followers lists to be private and won't return * anything if any user_id parameter is passed. * + * @brief Returns either the friends of the follower list + * * @param string $qtype Either "friends" or "followers" * @return boolean|array * @throws ForbiddenException @@ -3167,10 +3337,10 @@ function api_statuses_f($qtype) return false; } + $sql_extra = ''; if ($qtype == 'friends') { $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND)); - } - if ($qtype == 'followers') { + } elseif ($qtype == 'followers') { $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_FOLLOWER), intval(CONTACT_IS_FRIEND)); } @@ -3201,7 +3371,7 @@ function api_statuses_f($qtype) intval($count) ); - $ret = array(); + $ret = []; foreach ($r as $cid) { $user = api_get_user($a, $cid['nurl']); // "uid" and "self" are only needed for some internal stuff, so remove it from here @@ -3213,11 +3383,13 @@ function api_statuses_f($qtype) } } - return array('user' => $ret); + return ['user' => $ret]; } /** + * Returns the user's friends. + * * @brief Returns the list of friends of the provided user * * @deprecated By Twitter API in favor of friends/list @@ -3235,7 +3407,9 @@ function api_statuses_friends($type) } /** - * @brief Returns the list of friends of the provided user + * Returns the user's followers. + * + * @brief Returns the list of followers of the provided user * * @deprecated By Twitter API in favor of friends/list * @@ -3263,7 +3437,6 @@ api_register_func('api/statuses/followers', 'api_statuses_followers', true); * @param string $type Either "json" or "xml" * * @return boolean|string|array - * @throws UnauthorizedException */ function api_blocks_list($type) { @@ -3285,7 +3458,6 @@ api_register_func('api/blocks/list', 'api_blocks_list', true); * @param string $type Either "json" or "xml" * * @return boolean|string|array - * @throws UnauthorizedException */ function api_friendships_incoming($type) { @@ -3294,17 +3466,24 @@ function api_friendships_incoming($type) return false; } - $ids = array(); + $ids = []; foreach ($data['user'] as $user) { $ids[] = $user['id']; } - return api_format_data("ids", $type, array('id' => $ids)); + return api_format_data("ids", $type, ['id' => $ids]); } /// @TODO move to top of file or somewhere better api_register_func('api/friendships/incoming', 'api_friendships_incoming', true); +/** + * Returns the instance's configuration information. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_statusnet_config($type) { $a = get_app(); @@ -3317,39 +3496,45 @@ function api_statusnet_config($type) $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']) { - $texlimit = string($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()) : ''); - $config = array( - 'site' => array('name' => $name,'server' => $server, 'theme' => 'default', 'path' => '', + $config = [ + 'site' => ['name' => $name,'server' => $server, 'theme' => 'default', 'path' => '', 'logo' => $logo, 'fancy' => true, 'language' => 'en', 'email' => $email, 'broughtby' => '', 'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => false, 'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl, 'shorturllength' => '30', - 'friendica' => array( + 'friendica' => [ 'FRIENDICA_PLATFORM' => FRIENDICA_PLATFORM, 'FRIENDICA_VERSION' => FRIENDICA_VERSION, 'DFRN_PROTOCOL_VERSION' => DFRN_PROTOCOL_VERSION, 'DB_UPDATE_VERSION' => DB_UPDATE_VERSION - ) - ), - ); + ] + ], + ]; - return api_format_data('config', $type, array('config' => $config)); + return api_format_data('config', $type, ['config' => $config]); } /// @TODO move to top of file or somewhere better api_register_func('api/gnusocial/config', 'api_statusnet_config', false); api_register_func('api/statusnet/config', 'api_statusnet_config', false); +/** + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_statusnet_version($type) { // liar $fake_statusnet_version = "0.9.7"; - return api_format_data('version', $type, array('version' => $fake_statusnet_version)); + return api_format_data('version', $type, ['version' => $fake_statusnet_version]); } /// @TODO move to top of file or somewhere better @@ -3357,30 +3542,22 @@ api_register_func('api/gnusocial/version', 'api_statusnet_version', false); api_register_func('api/statusnet/version', 'api_statusnet_version', false); /** + * + * @param string $type Return type (atom, rss, xml, json) + * * @todo use api_format_data() to return data */ -function api_ff_ids($type,$qtype) +function api_ff_ids($type) { - $a = get_app(); - if (! api_user()) { throw new ForbiddenException(); } - $user_info = api_get_user($a); - - if ($qtype == 'friends') { - $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_SHARING), intval(CONTACT_IS_FRIEND)); - } - if ($qtype == 'followers') { - $sql_extra = sprintf(" AND ( `rel` = %d OR `rel` = %d ) ", intval(CONTACT_IS_FOLLOWER), intval(CONTACT_IS_FRIEND)); - } + $a = get_app(); - if (!$user_info["self"]) { - $sql_extra = " AND false "; - } + api_get_user($a); - $stringify_ids = (x($_REQUEST, 'stringify_ids') ? $_REQUEST['stringify_ids'] : false); + $stringify_ids = defaults($_REQUEST, 'stringify_ids', false); $r = q( "SELECT `pcontact`.`id` FROM `contact` @@ -3388,12 +3565,11 @@ function api_ff_ids($type,$qtype) WHERE `contact`.`uid` = %s AND NOT `contact`.`self`", intval(api_user()) ); - if (!DBM::is_result($r)) { return; } - $ids = array(); + $ids = []; foreach ($r as $rr) { if ($stringify_ids) { $ids[] = $rr['id']; @@ -3402,31 +3578,59 @@ function api_ff_ids($type,$qtype) } } - return api_format_data("ids", $type, array('id' => $ids)); + return api_format_data("ids", $type, ['id' => $ids]); } +/** + * Returns the ID of every user the user is following. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids + */ function api_friends_ids($type) { - return api_ff_ids($type, 'friends'); + return api_ff_ids($type); } +/** + * Returns the ID of every user following the user. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids + */ function api_followers_ids($type) { - return api_ff_ids($type, 'followers'); + return api_ff_ids($type); } /// @TODO move to top of file or somewhere better api_register_func('api/friends/ids', 'api_friends_ids', true); api_register_func('api/followers/ids', 'api_followers_ids', true); +/** + * Sends a new direct message. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-message + */ function api_direct_messages_new($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); + if (api_user() === false) { + throw new ForbiddenException(); + } - if (!x($_POST, "text") || (!x($_POST, "screen_name") && !x($_POST, "user_id"))) return; + if (!x($_POST, "text") || (!x($_POST, "screen_name") && !x($_POST, "user_id"))) { + return; + } $sender = api_get_user($a); @@ -3463,35 +3667,37 @@ function api_direct_messages_new($type) } } - $id = send_message($recipient['cid'], $_POST['text'], $sub, $replyto); + $id = Mail::send($recipient['cid'], $_POST['text'], $sub, $replyto); if ($id > -1) { $r = q("SELECT * FROM `mail` WHERE id=%d", intval($id)); $ret = api_format_messages($r[0], $recipient, $sender); } else { - $ret = array("error"=>$id); + $ret = ["error"=>$id]; } - $data = array('direct_message'=>$ret); + $data = ['direct_message'=>$ret]; switch ($type) { case "atom": case "rss": - $data = api_rss_extra($a, $data, $user_info); + $data = api_rss_extra($a, $data, $sender); } return api_format_data("direct-messages", $type, $data); - } /// @TODO move to top of file or somewhere better api_register_func('api/direct_messages/new', 'api_direct_messages_new', true, API_METHOD_POST); /** + * Destroys a direct message. + * * @brief delete a direct_message from mail table through api * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @return string + * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message */ function api_direct_messages_destroy($type) { @@ -3513,8 +3719,8 @@ function api_direct_messages_destroy($type) $uid = $user_info['uid']; // error if no id or parenturi specified (for clients posting parent-uri as well) if ($verbose == "true" && ($id == 0 || $parenturi == "")) { - $answer = array('result' => 'error', 'message' => 'message id or parenturi not specified'); - return api_format_data("direct_messages_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'message id or parenturi not specified']; + return api_format_data("direct_messages_delete", $type, ['$result' => $answer]); } // BadRequestException if no id specified (for clients using Twitter API) @@ -3535,8 +3741,8 @@ function api_direct_messages_destroy($type) // error message if specified id is not in database if (!DBM::is_result($r)) { if ($verbose == "true") { - $answer = array('result' => 'error', 'message' => 'message id not in database'); - return api_format_data("direct_messages_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'message id not in database']; + return api_format_data("direct_messages_delete", $type, ['$result' => $answer]); } /// @todo BadRequestException ok for Twitter API clients? throw new BadRequestException('message id not in database'); @@ -3552,20 +3758,27 @@ function api_direct_messages_destroy($type) if ($verbose == "true") { if ($result) { // return success - $answer = array('result' => 'ok', 'message' => 'message deleted'); - return api_format_data("direct_message_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'ok', 'message' => 'message deleted']; + return api_format_data("direct_message_delete", $type, ['$result' => $answer]); } else { - $answer = array('result' => 'error', 'message' => 'unknown error'); - return api_format_data("direct_messages_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'unknown error']; + return api_format_data("direct_messages_delete", $type, ['$result' => $answer]); } } /// @todo return JSON data like Twitter API not yet implemented - } /// @TODO move to top of file or somewhere better api_register_func('api/direct_messages/destroy', 'api_direct_messages_destroy', true, API_METHOD_DELETE); +/** + * + * @param string $type Return type (atom, rss, xml, json) + * @param string $box + * @param string $verbose + * + * @return array|string + */ function api_direct_messages_box($type, $box, $verbose) { $a = get_app(); @@ -3600,6 +3813,8 @@ function api_direct_messages_box($type, $box, $verbose) // pagination $start = $page * $count; + $sql_extra = ""; + // filters if ($box=="sentbox") { $sql_extra = "`mail`.`from-url`='" . dbesc($profile_url) . "'"; @@ -3629,11 +3844,11 @@ function api_direct_messages_box($type, $box, $verbose) intval($count) ); if ($verbose == "true" && !DBM::is_result($r)) { - $answer = array('result' => 'error', 'message' => 'no mails available'); - return api_format_data("direct_messages_all", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'no mails available']; + return api_format_data("direct_messages_all", $type, ['$result' => $answer]); } - $ret = array(); + $ret = []; foreach ($r as $item) { if ($box == "inbox" || $item['from-url'] != $profile_url) { $recipient = $user_info; @@ -3647,7 +3862,7 @@ function api_direct_messages_box($type, $box, $verbose) } - $data = array('direct_message' => $ret); + $data = ['direct_message' => $ret]; switch ($type) { case "atom": case "rss": @@ -3657,24 +3872,52 @@ function api_direct_messages_box($type, $box, $verbose) return api_format_data("direct-messages", $type, $data); } +/** + * Returns the most recent direct messages sent by the user. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-sent-message + */ function api_direct_messages_sentbox($type) { $verbose = (x($_GET, 'friendica_verbose') ? strtolower($_GET['friendica_verbose']) : "false"); return api_direct_messages_box($type, "sentbox", $verbose); } +/** + * Returns the most recent direct messages sent to the user. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + * @see https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-messages + */ function api_direct_messages_inbox($type) { $verbose = (x($_GET, 'friendica_verbose') ? strtolower($_GET['friendica_verbose']) : "false"); return api_direct_messages_box($type, "inbox", $verbose); } +/** + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_direct_messages_all($type) { $verbose = (x($_GET, 'friendica_verbose') ? strtolower($_GET['friendica_verbose']) : "false"); return api_direct_messages_box($type, "all", $verbose); } +/** + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_direct_messages_conversation($type) { $verbose = (x($_GET, 'friendica_verbose') ? strtolower($_GET['friendica_verbose']) : "false"); @@ -3687,7 +3930,12 @@ api_register_func('api/direct_messages/all', 'api_direct_messages_all', true); api_register_func('api/direct_messages/sent', 'api_direct_messages_sentbox', true); api_register_func('api/direct_messages', 'api_direct_messages_inbox', true); -function api_oauth_request_token($type) +/** + * Returns an OAuth Request Token. + * + * @see https://oauth.net/core/1.0/#auth_step1 + */ +function api_oauth_request_token() { $oauth1 = new FKOAuth1(); try { @@ -3700,7 +3948,13 @@ function api_oauth_request_token($type) killme(); } -function api_oauth_access_token($type) +/** + * Returns an OAuth Access Token. + * + * @return array|string + * @see https://oauth.net/core/1.0/#auth_step3 + */ +function api_oauth_access_token() { $oauth1 = new FKOAuth1(); try { @@ -3742,8 +3996,9 @@ function api_fr_photoalbum_delete($type) intval(api_user()), dbesc($album) ); - if (!DBM::is_result($r)) + if (!DBM::is_result($r)) { throw new BadRequestException("album not available"); + } // function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore // to the user and the contacts of the users (drop_items() performs the federation of the deletion to other networks @@ -3757,16 +4012,16 @@ function api_fr_photoalbum_delete($type) if (!DBM::is_result($photo_item)) { throw new InternalServerErrorException("problem with deleting items occured"); } - drop_item($photo_item[0]['id'], false); + Item::deleteById($photo_item[0]['id']); } // now let's delete all photos from the album - $result = dba::delete('photo', array('uid' => api_user(), 'album' => $album)); + $result = dba::delete('photo', ['uid' => api_user(), 'album' => $album]); // return success of deletion or error message if ($result) { - $answer = array('result' => 'deleted', 'message' => 'album `' . $album . '` with all containing photos has been deleted.'); - return api_format_data("photoalbum_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'deleted', 'message' => 'album `' . $album . '` with all containing photos has been deleted.']; + return api_format_data("photoalbum_delete", $type, ['$result' => $answer]); } else { throw new InternalServerErrorException("unknown error - deleting from database failed"); } @@ -3813,8 +4068,8 @@ function api_fr_photoalbum_update($type) // return success of updating or error message if ($result) { - $answer = array('result' => 'updated', 'message' => 'album `' . $album . '` with all containing photos has been renamed to `' . $album_new . '`.'); - return api_format_data("photoalbum_update", $type, array('$result' => $answer)); + $answer = ['result' => 'updated', 'message' => 'album `' . $album . '` with all containing photos has been renamed to `' . $album_new . '`.']; + return api_format_data("photoalbum_update", $type, ['$result' => $answer]); } else { throw new InternalServerErrorException("unknown error - updating in database failed"); } @@ -3838,15 +4093,15 @@ function api_fr_photos_list($type) WHERE `uid` = %d AND `album` != 'Contact Photos' GROUP BY `resource-id`", intval(local_user()) ); - $typetoext = array( + $typetoext = [ 'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif' - ); - $data = array('photo'=>array()); + ]; + $data = ['photo'=>[]]; if (DBM::is_result($r)) { foreach ($r as $rr) { - $photo = array(); + $photo = []; $photo['id'] = $rr['resource-id']; $photo['album'] = $rr['album']; $photo['filename'] = $rr['filename']; @@ -3857,7 +4112,7 @@ function api_fr_photos_list($type) $photo['desc'] = $rr['desc']; if ($type == "xml") { - $data['photo'][] = array("@attributes" => $photo, "1" => $thumb); + $data['photo'][] = ["@attributes" => $photo, "1" => $thumb]; } else { $photo['thumb'] = $thumb; $data['photo'][] = $photo; @@ -3981,7 +4236,7 @@ function api_fr_photo_create_update($type) $result = q( "UPDATE `photo` SET %s, `edited`='%s' WHERE `uid` = %d AND `resource-id` = '%s' AND `album` = '%s'", $sql_extra, - datetime_convert(), // update edited timestamp + DateTimeFormat::utcNow(), // update edited timestamp intval(api_user()), dbesc($photo_id), dbesc($album) @@ -4001,12 +4256,12 @@ function api_fr_photo_create_update($type) // return success of updating or error message if ($result) { - $answer = array('result' => 'updated', 'message' => 'Image id `' . $photo_id . '` has been updated.'); - return api_format_data("photo_update", $type, array('$result' => $answer)); + $answer = ['result' => 'updated', 'message' => 'Image id `' . $photo_id . '` has been updated.']; + return api_format_data("photo_update", $type, ['$result' => $answer]); } else { if ($nothingtodo) { - $answer = array('result' => 'cancelled', 'message' => 'Nothing to update for image id `' . $photo_id . '`.'); - return api_format_data("photo_update", $type, array('$result' => $answer)); + $answer = ['result' => 'cancelled', 'message' => 'Nothing to update for image id `' . $photo_id . '`.']; + return api_format_data("photo_update", $type, ['$result' => $answer]); } throw new InternalServerErrorException("unknown error - update photo entry in database failed"); } @@ -4044,7 +4299,7 @@ function api_fr_photo_delete($type) throw new BadRequestException("photo not available"); } // now we can perform on the deletion of the photo - $result = dba::delete('photo', array('uid' => api_user(), 'resource-id' => $photo_id)); + $result = dba::delete('photo', ['uid' => api_user(), 'resource-id' => $photo_id]); // return success of deletion or error message if ($result) { @@ -4060,10 +4315,10 @@ function api_fr_photo_delete($type) } // function for setting the items to "deleted = 1" which ensures that comments, likes etc. are not shown anymore // to the user and the contacts of the users (drop_items() do all the necessary magic to avoid orphans in database and federate deletion) - drop_item($photo_item[0]['id'], false); + Item::deleteById($photo_item[0]['id']); - $answer = array('result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.'); - return api_format_data("photo_delete", $type, array('$result' => $answer)); + $answer = ['result' => 'deleted', 'message' => 'photo with id `' . $photo_id . '` has been deleted from server.']; + return api_format_data("photo_delete", $type, ['$result' => $answer]); } else { throw new InternalServerErrorException("unknown error on deleting photo from database table"); } @@ -4074,7 +4329,7 @@ function api_fr_photo_delete($type) * @brief returns the details of a specified photo id, if scale is given, returns the photo data in base 64 * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string + * @return string|array */ function api_fr_photo_detail($type) { @@ -4096,10 +4351,14 @@ function api_fr_photo_detail($type) /** + * Updates the user’s profile image. + * * @brief updates the profile image for the user (either a specified profile or the default profile) * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' + * * @return string + * @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image */ function api_account_update_profile_image($type) { @@ -4107,7 +4366,7 @@ function api_account_update_profile_image($type) throw new ForbiddenException(); } // input params - $profileid = (x($_REQUEST, 'profile_id') ? $_REQUEST['profile_id'] : 0); + $profileid = defaults($_REQUEST, 'profile_id', 0); // error if image data is missing if (!x($_FILES, 'image')) { @@ -4138,7 +4397,7 @@ function api_account_update_profile_image($type) $media = $_FILES['media']; } // save new profile image - $data = save_media_to_database("profileimage", $media, $type, t('Profile Photos'), "", "", "", "", "", $is_default_profile); + $data = save_media_to_database("profileimage", $media, $type, L10n::t('Profile Photos'), "", "", "", "", "", $is_default_profile); // get filetype if (is_array($media['type'])) { @@ -4153,13 +4412,13 @@ function api_account_update_profile_image($type) } // change specified profile or all profiles to the new resource-id if ($is_default_profile) { - $r = q( + q( "UPDATE `photo` SET `profile` = 0 WHERE `profile` = 1 AND `resource-id` != '%s' AND `uid` = %d", dbesc($data['photo']['id']), intval(local_user()) ); - $r = q( + q( "UPDATE `contact` SET `photo` = '%s', `thumb` = '%s', `micro` = '%s' WHERE `self` AND `uid` = %d", dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-4.' . $fileext), dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-5.' . $fileext), @@ -4167,7 +4426,7 @@ function api_account_update_profile_image($type) intval(local_user()) ); } else { - $r = q( + q( "UPDATE `profile` SET `photo` = '%s', `thumb` = '%s' WHERE `id` = %d AND `uid` = %d", dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-4.' . $filetype), dbesc(System::baseUrl() . '/photo/' . $data['photo']['id'] . '-5.' . $filetype), @@ -4179,9 +4438,9 @@ function api_account_update_profile_image($type) // we'll set the updated profile-photo timestamp even if it isn't the default profile, // so that browsers will do a cache update unconditionally - $r = q( + q( "UPDATE `contact` SET `avatar-date` = '%s' WHERE `self` = 1 AND `uid` = %d", - dbesc(datetime_convert()), + dbesc(DateTimeFormat::utcNow()), intval(local_user()) ); @@ -4213,7 +4472,47 @@ api_register_func('api/friendica/photo/delete', 'api_fr_photo_delete', true, API api_register_func('api/friendica/photo', 'api_fr_photo_detail', true); api_register_func('api/account/update_profile_image', 'api_account_update_profile_image', true, API_METHOD_POST); +/** + * Update user profile + * + * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' + * + * @return array|string + */ +function api_account_update_profile($type) +{ + $local_user = api_user(); + $api_user = api_get_user(get_app()); + + if (!empty($_POST['name'])) { + dba::update('profile', ['name' => $_POST['name']], ['uid' => $local_user]); + dba::update('user', ['username' => $_POST['name']], ['uid' => $local_user]); + dba::update('contact', ['name' => $_POST['name']], ['uid' => $local_user, 'self' => 1]); + dba::update('contact', ['name' => $_POST['name']], ['id' => $api_user['id']]); + } + + if (isset($_POST['description'])) { + dba::update('profile', ['about' => $_POST['description']], ['uid' => $local_user]); + dba::update('contact', ['about' => $_POST['description']], ['uid' => $local_user, 'self' => 1]); + dba::update('contact', ['about' => $_POST['description']], ['id' => $api_user['id']]); + } + Worker::add(PRIORITY_LOW, 'ProfileUpdate', $local_user); + // Update global directory in background + if ($api_user['url'] && strlen(Config::get('system', 'directory'))) { + Worker::add(PRIORITY_LOW, "Directory", $api_user['url']); + } + + return api_account_verify_credentials($type); +} + +/// @TODO move to top of file or somewhere better +api_register_func('api/account/update_profile', 'api_account_update_profile', true, API_METHOD_POST); + +/** + * + * @param string $acl_string + */ function check_acl_input($acl_string) { if ($acl_string == null || $acl_string == " ") { @@ -4239,6 +4538,21 @@ function check_acl_input($acl_string) return $contact_not_found; } +/** + * + * @param string $mediatype + * @param array $media + * @param string $type + * @param string $album + * @param string $allow_cid + * @param string $deny_cid + * @param string $allow_gid + * @param string $deny_gid + * @param string $desc + * @param integer $profile + * @param boolean $visibility + * @param string $photo_id + */ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $desc, $profile = 0, $visibility = false, $photo_id = null) { $visitor = 0; @@ -4279,7 +4593,8 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ } logger( "File upload src: " . $src . " - filename: " . $filename . - " - size: " . $filesize . " - type: " . $filetype, LOGGER_DEBUG + " - size: " . $filesize . " - type: " . $filetype, + LOGGER_DEBUG ); // check if there was a php upload error @@ -4288,7 +4603,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ } // check against max upload size within Friendica instance $maximagesize = Config::get('system', 'maximagesize'); - if (($maximagesize) && ($filesize > $maximagesize)) { + if ($maximagesize && ($filesize > $maximagesize)) { $formattedBytes = formatBytes($maximagesize); throw new InternalServerErrorException("image size exceeds Friendica config setting (uploaded size: $formattedBytes)"); } @@ -4317,7 +4632,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ $height = $Image->getHeight(); // create a new resource-id if not already provided - $hash = ($photo_id == null) ? photo_new_resource() : $photo_id; + $hash = ($photo_id == null) ? Photo::newResource() : $photo_id; if ($mediatype == "photo") { // upload normal image (scales 0, 1, 2) @@ -4386,13 +4701,23 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ } } +/** + * + * @param string $hash + * @param string $allow_cid + * @param string $deny_cid + * @param string $allow_gid + * @param string $deny_gid + * @param string $filetype + * @param boolean $visibility + */ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $filetype, $visibility = false) { // get data about the api authenticated user $uri = item_new_uri(get_app()->get_hostname(), intval(api_user())); $owner_record = q("SELECT * FROM `contact` WHERE `uid`= %d AND `self` LIMIT 1", intval(api_user())); - $arr = array(); + $arr = []; $arr['guid'] = get_guid(32); $arr['uid'] = intval(api_user()); $arr['uri'] = $uri; @@ -4412,15 +4737,14 @@ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $f $arr['allow_gid'] = $allow_gid; $arr['deny_cid'] = $deny_cid; $arr['deny_gid'] = $deny_gid; - $arr['last-child'] = 1; $arr['visible'] = $visibility; $arr['origin'] = 1; - $typetoext = array( + $typetoext = [ 'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif' - ); + ]; // adds link to the thumbnail scale photo $arr['body'] = '[url=' . System::baseUrl() . '/photos/' . $owner_record[0]['nick'] . '/image/' . $hash . ']' @@ -4428,9 +4752,17 @@ function post_photo_item($hash, $allow_cid, $deny_cid, $allow_gid, $deny_gid, $f . '[/url]'; // do the magic for storing the item in the database and trigger the federation to other contacts - item_store($arr); + Item::insert($arr); } +/** + * + * @param string $type + * @param int $scale + * @param string $photo_id + * + * @return array + */ function prepare_photo_data($type, $scale, $photo_id) { $scale_sql = ($scale === false ? "" : sprintf("AND scale=%d", intval($scale))); @@ -4449,15 +4781,15 @@ function prepare_photo_data($type, $scale, $photo_id) $scale_sql ); - $typetoext = array( + $typetoext = [ 'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif' - ); + ]; // prepare output data for photo if (DBM::is_result($r)) { - $data = array('photo' => $r[0]); + $data = ['photo' => $r[0]]; $data['photo']['id'] = $data['photo']['resource-id']; if ($scale !== false) { $data['photo']['data'] = base64_encode($data['photo']['data']); @@ -4465,14 +4797,14 @@ function prepare_photo_data($type, $scale, $photo_id) unset($data['photo']['datasize']); //needed only with scale param } if ($type == "xml") { - $data['photo']['links'] = array(); + $data['photo']['links'] = []; for ($k = intval($data['photo']['minscale']); $k <= intval($data['photo']['maxscale']); $k++) { - $data['photo']['links'][$k . ":link"]["@attributes"] = array("type" => $data['photo']['type'], + $data['photo']['links'][$k . ":link"]["@attributes"] = ["type" => $data['photo']['type'], "scale" => $k, - "href" => System::baseUrl() . "/photo/" . $data['photo']['resource-id'] . "-" . $k . "." . $typetoext[$data['photo']['type']]); + "href" => System::baseUrl() . "/photo/" . $data['photo']['resource-id'] . "-" . $k . "." . $typetoext[$data['photo']['type']]]; } } else { - $data['photo']['link'] = array(); + $data['photo']['link'] = []; // when we have profile images we could have only scales from 4 to 6, but index of array always needs to start with 0 $i = 0; for ($k = intval($data['photo']['minscale']); $k <= intval($data['photo']['maxscale']); $k++) { @@ -4514,7 +4846,7 @@ function prepare_photo_data($type, $scale, $photo_id) // prepare output of comments $commentData = api_format_items($r, api_get_user(get_app()), false, $type); - $comments = array(); + $comments = []; if ($type == "xml") { $k = 0; foreach ($commentData as $comment) { @@ -4551,8 +4883,8 @@ function prepare_photo_data($type, $scale, $photo_id) */ function api_friendica_remoteauth() { - $url = ((x($_GET, 'url')) ? $_GET['url'] : ''); - $c_url = ((x($_GET, 'c_url')) ? $_GET['c_url'] : ''); + $url = (x($_GET, 'url') ? $_GET['url'] : ''); + $c_url = (x($_GET, 'c_url') ? $_GET['c_url'] : ''); if ($url === '' || $c_url === '') { throw new BadRequestException("Wrong parameters."); @@ -4562,26 +4894,22 @@ function api_friendica_remoteauth() // traditional DFRN - $r = q( - "SELECT * FROM `contact` WHERE `id` = %d AND `nurl` = '%s' LIMIT 1", - dbesc($c_url), - intval(api_user()) - ); + $contact = dba::selectFirst('contact', [], ['uid' => api_user(), 'nurl' => $c_url]); - if ((! DBM::is_result($r)) || ($r[0]['network'] !== NETWORK_DFRN)) { + if (!DBM::is_result($contact) || ($contact['network'] !== NETWORK_DFRN)) { throw new BadRequestException("Unknown contact"); } - $cid = $r[0]['id']; + $cid = $contact['id']; - $dfrn_id = $orig_id = (($r[0]['issued-id']) ? $r[0]['issued-id'] : $r[0]['dfrn-id']); + $dfrn_id = defaults($contact, 'issued-id', $contact['dfrn-id']); - if ($r[0]['duplex'] && $r[0]['issued-id']) { - $orig_id = $r[0]['issued-id']; + if ($contact['duplex'] && $contact['issued-id']) { + $orig_id = $contact['issued-id']; $dfrn_id = '1:' . $orig_id; } - if ($r[0]['duplex'] && $r[0]['dfrn-id']) { - $orig_id = $r[0]['dfrn-id']; + if ($contact['duplex'] && $contact['dfrn-id']) { + $orig_id = $contact['dfrn-id']; $dfrn_id = '0:' . $orig_id; } @@ -4597,12 +4925,12 @@ function api_friendica_remoteauth() intval(time() + 45) ); - logger($r[0]['name'] . ' ' . $sec, LOGGER_DEBUG); - $dest = (($url) ? '&destination_url=' . $url : ''); + logger($contact['name'] . ' ' . $sec, LOGGER_DEBUG); + $dest = ($url ? '&destination_url=' . $url : ''); goaway( - $r[0]['poll'] . '?dfrn_id=' . $dfrn_id + $contact['poll'] . '?dfrn_id=' . $dfrn_id . '&dfrn_version=' . DFRN_PROTOCOL_VERSION - . '&type=profile&sec=' . $sec . $dest . $quiet + . '&type=profile&sec=' . $sec . $dest ); } api_register_func('api/friendica/remoteauth', 'api_friendica_remoteauth', true); @@ -4611,7 +4939,7 @@ api_register_func('api/friendica/remoteauth', 'api_friendica_remoteauth', true); * @brief Return the item shared, if the item contains only the [share] tag * * @param array $item Sharer item - * @return array Shared item or false if not a reshare + * @return array|false Shared item or false if not a reshare */ function api_share_as_retweet(&$item) { @@ -4682,8 +5010,9 @@ function api_share_as_retweet(&$item) $posted = ""; preg_match("/posted='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") + if ($matches[1] != "") { $posted = $matches[1]; + } preg_match('/posted="(.*?)"/ism', $attributes, $matches); if ($matches[1] != "") { @@ -4705,16 +5034,18 @@ function api_share_as_retweet(&$item) $reshared_item["edited"] = $posted; return $reshared_item; - } +/** + * + * @param string $profile + * + * @return string|false + * @todo remove trailing junk from profile url + * @todo pump.io check has to check the website + */ function api_get_nick($profile) { - /* To-Do: - - remove trailing junk from profile url - - pump.io check has to check the website - */ - $nick = ""; $r = q( @@ -4764,7 +5095,7 @@ function api_get_nick($profile) if ($StatusnetHost != $profile) { $StatusnetUser = preg_replace("=https?://(.*)/user/(.*)=ism", "$2", $profile); if ($StatusnetUser != $profile) { - $UserData = fetch_url("http://".$StatusnetHost."/api/users/show.json?user_id=".$StatusnetUser); + $UserData = Network::fetchUrl("http://".$StatusnetHost."/api/users/show.json?user_id=".$StatusnetUser); $user = json_decode($UserData); if ($user) { $nick = $user->screen_name; @@ -4789,9 +5120,15 @@ function api_get_nick($profile) return false; } +/** + * + * @param array $item + * + * @return array + */ function api_in_reply_to($item) { - $in_reply_to = array(); + $in_reply_to = []; $in_reply_to['status_id'] = null; $in_reply_to['user_id'] = null; @@ -4800,9 +5137,11 @@ function api_in_reply_to($item) $in_reply_to['screen_name'] = null; if (($item['thr-parent'] != $item['uri']) && (intval($item['parent']) != intval($item['id']))) { - $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", + $r = q( + "SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1", intval($item['uid']), - dbesc($item['thr-parent'])); + dbesc($item['thr-parent']) + ); if (DBM::is_result($r)) { $in_reply_to['status_id'] = intval($r[0]['id']); @@ -4812,7 +5151,8 @@ function api_in_reply_to($item) $in_reply_to['status_id_str'] = (string) intval($in_reply_to['status_id']); - $r = q("SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item + $r = q( + "SELECT `contact`.`nick`, `contact`.`name`, `contact`.`id`, `contact`.`url` FROM item STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`author-id` WHERE `item`.`id` = %d LIMIT 1", intval($in_reply_to['status_id']) @@ -4844,11 +5184,17 @@ function api_in_reply_to($item) return $in_reply_to; } +/** + * + * @param string $Text + * + * @return string + */ function api_clean_plain_items($Text) { $include_entities = strtolower(x($_REQUEST, 'include_entities') ? $_REQUEST['include_entities'] : "false"); - $Text = bb_CleanPictureLinks($Text); + $Text = BBCode::cleanPictureLinks($Text); $URLSearchString = "^\[\]"; $Text = preg_replace("/([!#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $Text); @@ -4872,78 +5218,109 @@ function api_clean_plain_items($Text) */ function api_clean_attachments($body) { - $data = get_attachment_data($body); + $data = BBCode::getAttachmentData($body); - if (!$data) + if (!$data) { return $body; - + } $body = ""; - if (isset($data["text"])) + if (isset($data["text"])) { $body = $data["text"]; - - if (($body == "") && (isset($data["title"]))) + } + if (($body == "") && isset($data["title"])) { $body = $data["title"]; - - if (isset($data["url"])) + } + if (isset($data["url"])) { $body .= "\n".$data["url"]; - + } $body .= $data["after"]; return $body; } +/** + * + * @param array $contacts + * + * @return array + */ function api_best_nickname(&$contacts) { - $best_contact = array(); + $best_contact = []; - if (count($contact) == 0) + if (count($contacts) == 0) { return; + } - foreach ($contacts as $contact) + foreach ($contacts as $contact) { if ($contact["network"] == "") { $contact["network"] = "dfrn"; - $best_contact = array($contact); + $best_contact = [$contact]; } + } - if (sizeof($best_contact) == 0) - foreach ($contacts as $contact) - if ($contact["network"] == "dfrn") - $best_contact = array($contact); + if (sizeof($best_contact) == 0) { + foreach ($contacts as $contact) { + if ($contact["network"] == "dfrn") { + $best_contact = [$contact]; + } + } + } - if (sizeof($best_contact) == 0) - foreach ($contacts as $contact) - if ($contact["network"] == "dspr") - $best_contact = array($contact); + if (sizeof($best_contact) == 0) { + foreach ($contacts as $contact) { + if ($contact["network"] == "dspr") { + $best_contact = [$contact]; + } + } + } - if (sizeof($best_contact) == 0) - foreach ($contacts as $contact) - if ($contact["network"] == "stat") - $best_contact = array($contact); + if (sizeof($best_contact) == 0) { + foreach ($contacts as $contact) { + if ($contact["network"] == "stat") { + $best_contact = [$contact]; + } + } + } - if (sizeof($best_contact) == 0) - foreach ($contacts as $contact) - if ($contact["network"] == "pump") - $best_contact = array($contact); + if (sizeof($best_contact) == 0) { + foreach ($contacts as $contact) { + if ($contact["network"] == "pump") { + $best_contact = [$contact]; + } + } + } - if (sizeof($best_contact) == 0) - foreach ($contacts as $contact) - if ($contact["network"] == "twit") - $best_contact = array($contact); + if (sizeof($best_contact) == 0) { + foreach ($contacts as $contact) { + if ($contact["network"] == "twit") { + $best_contact = [$contact]; + } + } + } if (sizeof($best_contact) == 1) { $contacts = $best_contact; } else { - $contacts = array($contacts[0]); + $contacts = [$contacts[0]]; } } -// return all or a specified group of the user with the containing contacts +/** + * Return all or a specified group of the user with the containing contacts. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_friendica_group_show($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); + if (api_user() === false) { + throw new ForbiddenException(); + } // params $user_info = api_get_user($a); @@ -4958,8 +5335,9 @@ function api_friendica_group_show($type) intval($gid) ); // error message if specified gid is not in database - if (!DBM::is_result($r)) + if (!DBM::is_result($r)) { throw new BadRequestException("gid not available"); + } } else { $r = q( "SELECT * FROM `group` WHERE `deleted` = 0 AND `uid` = %d", @@ -4970,7 +5348,7 @@ function api_friendica_group_show($type) // loop through all groups and retrieve all members for adding data in the user array foreach ($r as $rr) { $members = Contact::getByGroupId($rr['id']); - $users = array(); + $users = []; if ($type == "xml") { $user_element = "users"; @@ -4986,14 +5364,20 @@ function api_friendica_group_show($type) $users[] = $user; } } - $grps[] = array('name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users); + $grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users]; } - return api_format_data("groups", $type, array('group' => $grps)); + return api_format_data("groups", $type, ['group' => $grps]); } api_register_func('api/friendica/group_show', 'api_friendica_group_show', true); -// delete the specified group of the user +/** + * Delete the specified group of the user. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_friendica_group_delete($type) { $a = get_app(); @@ -5040,8 +5424,8 @@ function api_friendica_group_delete($type) $ret = Group::removeByName($uid, $name); if ($ret) { // return success - $success = array('success' => $ret, 'gid' => $gid, 'name' => $name, 'status' => 'deleted', 'wrong users' => array()); - return api_format_data("group_delete", $type, array('result' => $success)); + $success = ['success' => $ret, 'gid' => $gid, 'name' => $name, 'status' => 'deleted', 'wrong users' => []]; + return api_format_data("group_delete", $type, ['result' => $success]); } else { throw new BadRequestException('other API error'); } @@ -5049,12 +5433,20 @@ function api_friendica_group_delete($type) api_register_func('api/friendica/group_delete', 'api_friendica_group_delete', true, API_METHOD_DELETE); -// create the specified group with the posted array of contacts +/** + * Create the specified group with the posted array of contacts. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_friendica_group_create($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); + if (api_user() === false) { + throw new ForbiddenException(); + } // params $user_info = api_get_user($a); @@ -5064,8 +5456,9 @@ function api_friendica_group_create($type) $users = $json['user']; // error if no name specified - if ($name == "") + if ($name == "") { throw new BadRequestException('group name not specified'); + } // get data of the specified group name $rname = q( @@ -5074,8 +5467,9 @@ function api_friendica_group_create($type) dbesc($name) ); // error message if specified group name already exists - if (DBM::is_result($rname)) + if (DBM::is_result($rname)) { throw new BadRequestException('group name already exists'); + } // check if specified group name is a deleted group $rname = q( @@ -5084,8 +5478,9 @@ function api_friendica_group_create($type) dbesc($name) ); // error message if specified group name already exists - if (DBM::is_result($rname)) + if (DBM::is_result($rname)) { $reactivate_group = true; + } // create group $ret = Group::create($uid, $name); @@ -5097,7 +5492,7 @@ function api_friendica_group_create($type) // add members $erroraddinguser = false; - $errorusers = array(); + $errorusers = []; foreach ($users as $user) { $cid = $user['cid']; // check if user really exists as contact @@ -5106,9 +5501,9 @@ function api_friendica_group_create($type) intval($cid), intval($uid) ); - if (count($contact)) - $result = Group::addMember($gid, $cid); - else { + if (count($contact)) { + Group::addMember($gid, $cid); + } else { $erroraddinguser = true; $errorusers[] = $cid; } @@ -5116,18 +5511,26 @@ function api_friendica_group_create($type) // return success message incl. missing users in array $status = ($erroraddinguser ? "missing user" : ($reactivate_group ? "reactivated" : "ok")); - $success = array('success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers); - return api_format_data("group_create", $type, array('result' => $success)); + $success = ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers]; + return api_format_data("group_create", $type, ['result' => $success]); } api_register_func('api/friendica/group_create', 'api_friendica_group_create', true, API_METHOD_POST); -// update the specified group with the posted array of contacts +/** + * Update the specified group with the posted array of contacts. + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_friendica_group_update($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); + if (api_user() === false) { + throw new ForbiddenException(); + } // params $user_info = api_get_user($a); @@ -5138,12 +5541,14 @@ function api_friendica_group_update($type) $users = $json['user']; // error if no name specified - if ($name == "") + if ($name == "") { throw new BadRequestException('group name not specified'); + } // error if no gid specified - if ($gid == "") + if ($gid == "") { throw new BadRequestException('gid not specified'); + } // remove members $members = Contact::getByGroupId($gid); @@ -5153,13 +5558,13 @@ function api_friendica_group_update($type) $found = ($user['cid'] == $cid ? true : false); } if (!$found) { - $ret = Group::removeMemberByName($uid, $name, $cid); + Group::removeMemberByName($uid, $name, $cid); } } // add members $erroraddinguser = false; - $errorusers = array(); + $errorusers = []; foreach ($users as $user) { $cid = $user['cid']; // check if user really exists as contact @@ -5170,7 +5575,7 @@ function api_friendica_group_update($type) ); if (count($contact)) { - $result = Group::addMember($gid, $cid); + Group::addMember($gid, $cid); } else { $erroraddinguser = true; $errorusers[] = $cid; @@ -5179,23 +5584,31 @@ function api_friendica_group_update($type) // return success message incl. missing users in array $status = ($erroraddinguser ? "missing user" : "ok"); - $success = array('success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers); - return api_format_data("group_update", $type, array('result' => $success)); + $success = ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers]; + return api_format_data("group_update", $type, ['result' => $success]); } api_register_func('api/friendica/group_update', 'api_friendica_group_update', true, API_METHOD_POST); +/** + * + * @param string $type Return type (atom, rss, xml, json) + * + * @return array|string + */ function api_friendica_activity($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); + if (api_user() === false) { + throw new ForbiddenException(); + } $verb = strtolower($a->argv[3]); $verb = preg_replace("|\..*$|", "", $verb); $id = (x($_REQUEST, 'id') ? $_REQUEST['id'] : 0); - $res = do_like($id, $verb); + $res = Item::performLike($id, $verb); if ($res) { if ($type == "xml") { @@ -5203,13 +5616,13 @@ function api_friendica_activity($type) } else { $ok = "ok"; } - return api_format_data('ok', $type, array('ok' => $ok)); + return api_format_data('ok', $type, ['ok' => $ok]); } else { throw new BadRequestException('Error adding activity'); } } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/friendica/activity/like', 'api_friendica_activity', true, API_METHOD_POST); api_register_func('api/friendica/activity/dislike', 'api_friendica_activity', true, API_METHOD_POST); api_register_func('api/friendica/activity/attendyes', 'api_friendica_activity', true, API_METHOD_POST); @@ -5231,28 +5644,33 @@ function api_friendica_notification($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); - if ($a->argc!==3) throw new BadRequestException("Invalid argument count"); + if (api_user() === false) { + throw new ForbiddenException(); + } + if ($a->argc!==3) { + throw new BadRequestException("Invalid argument count"); + } $nm = new NotificationsManager(); - $notes = $nm->getAll(array(), "+seen -date", 50); + $notes = $nm->getAll([], "+seen -date", 50); if ($type == "xml") { - $xmlnotes = array(); - foreach ($notes as $note) - $xmlnotes[] = array("@attributes" => $note); + $xmlnotes = []; + foreach ($notes as $note) { + $xmlnotes[] = ["@attributes" => $note]; + } $notes = $xmlnotes; } - return api_format_data("notes", $type, array('note' => $notes)); + return api_format_data("notes", $type, ['note' => $notes]); } /** - * @brief Set notification as seen and returns associated item (if possible) - * * POST request with 'id' param as notification id * + * @brief Set notification as seen and returns associated item (if possible) + * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' * @return string */ @@ -5260,14 +5678,20 @@ function api_friendica_notification_seen($type) { $a = get_app(); - if (api_user() === false) throw new ForbiddenException(); - if ($a->argc!==4) throw new BadRequestException("Invalid argument count"); + if (api_user() === false) { + throw new ForbiddenException(); + } + if ($a->argc!==4) { + throw new BadRequestException("Invalid argument count"); + } $id = (x($_REQUEST, 'id') ? intval($_REQUEST['id']) : 0); $nm = new NotificationsManager(); $note = $nm->getByID($id); - if (is_null($note)) throw new BadRequestException("Invalid argument"); + if (is_null($note)) { + throw new BadRequestException("Invalid argument"); + } $nm->setSeen($note); if ($note['otype']=='item') { @@ -5281,15 +5705,15 @@ function api_friendica_notification_seen($type) // we found the item, return it to the user $user_info = api_get_user($a); $ret = api_format_items($r, $user_info, false, $type); - $data = array('status' => $ret); + $data = ['status' => $ret]; return api_format_data("status", $type, $data); } // the item can't be found, but we set the note as seen, so we count this as a success } - return api_format_data('result', $type, array('result' => "success")); + return api_format_data('result', $type, ['result' => "success"]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/friendica/notification/seen', 'api_friendica_notification_seen', true, API_METHOD_POST); api_register_func('api/friendica/notification', 'api_friendica_notification', true, API_METHOD_GET); @@ -5313,8 +5737,8 @@ function api_friendica_direct_messages_setseen($type) // return error if id is zero if ($id == "") { - $answer = array('result' => 'error', 'message' => 'message id not specified'); - return api_format_data("direct_messages_setseen", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'message id not specified']; + return api_format_data("direct_messages_setseen", $type, ['$result' => $answer]); } // get data of the specified message id @@ -5326,8 +5750,8 @@ function api_friendica_direct_messages_setseen($type) // error message if specified id is not in database if (!DBM::is_result($r)) { - $answer = array('result' => 'error', 'message' => 'message id not in database'); - return api_format_data("direct_messages_setseen", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'message id not in database']; + return api_format_data("direct_messages_setseen", $type, ['$result' => $answer]); } // update seen indicator @@ -5339,26 +5763,27 @@ function api_friendica_direct_messages_setseen($type) if ($result) { // return success - $answer = array('result' => 'ok', 'message' => 'message set to seen'); - return api_format_data("direct_message_setseen", $type, array('$result' => $answer)); + $answer = ['result' => 'ok', 'message' => 'message set to seen']; + return api_format_data("direct_message_setseen", $type, ['$result' => $answer]); } else { - $answer = array('result' => 'error', 'message' => 'unknown error'); - return api_format_data("direct_messages_setseen", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'unknown error']; + return api_format_data("direct_messages_setseen", $type, ['$result' => $answer]); } } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/friendica/direct_messages_setseen', 'api_friendica_direct_messages_setseen', true); /** * @brief search for direct_messages containing a searchstring through api * * @param string $type Known types are 'atom', 'rss', 'xml' and 'json' - * @return string (success: success=true if found and search_result contains found messages + * @param string $box + * @return string (success: success=true if found and search_result contains found messages, * success=false if nothing was found, search_result='nothing found', * error: result=error with error message) */ -function api_friendica_direct_messages_search($type) +function api_friendica_direct_messages_search($type, $box = "") { $a = get_app(); @@ -5373,8 +5798,8 @@ function api_friendica_direct_messages_search($type) // error if no searchstring specified if ($searchstring == "") { - $answer = array('result' => 'error', 'message' => 'searchstring not specified'); - return api_format_data("direct_messages_search", $type, array('$result' => $answer)); + $answer = ['result' => 'error', 'message' => 'searchstring not specified']; + return api_format_data("direct_messages_search", $type, ['$result' => $answer]); } // get data for the specified searchstring @@ -5388,11 +5813,11 @@ function api_friendica_direct_messages_search($type) // message if nothing was found if (!DBM::is_result($r)) { - $success = array('success' => false, 'search_results' => 'problem with query'); + $success = ['success' => false, 'search_results' => 'problem with query']; } elseif (count($r) == 0) { - $success = array('success' => false, 'search_results' => 'nothing found'); + $success = ['success' => false, 'search_results' => 'nothing found']; } else { - $ret = array(); + $ret = []; foreach ($r as $item) { if ($box == "inbox" || $item['from-url'] != $profile_url) { $recipient = $user_info; @@ -5404,13 +5829,13 @@ function api_friendica_direct_messages_search($type) $ret[] = api_format_messages($item, $recipient, $sender); } - $success = array('success' => true, 'search_results' => $ret); + $success = ['success' => true, 'search_results' => $ret]; } - return api_format_data("direct_message_search", $type, array('$result' => $success)); + return api_format_data("direct_message_search", $type, ['$result' => $success]); } -/// @TODO move to top of file or somwhere better +/// @TODO move to top of file or somewhere better api_register_func('api/friendica/direct_messages_search', 'api_friendica_direct_messages_search', true); /** @@ -5455,10 +5880,10 @@ function api_friendica_profile_show($type) // loop through all returned profiles and retrieve data and users $k = 0; foreach ($r as $rr) { - $profile = api_format_items_profiles($rr, $type); + $profile = api_format_items_profiles($rr); // select all users from contact table, loop and prepare standard return for user data - $users = array(); + $users = []; $r = q( "SELECT `id`, `nurl` FROM `contact` WHERE `uid`= %d AND `profile-id` = %d", intval(api_user()), @@ -5482,26 +5907,59 @@ function api_friendica_profile_show($type) // return settings, authenticated user and profiles data $self = q("SELECT `nurl` FROM `contact` WHERE `uid`= %d AND `self` LIMIT 1", intval(api_user())); - $result = array('multi_profiles' => $multi_profiles ? true : false, + $result = ['multi_profiles' => $multi_profiles ? true : false, 'global_dir' => $directory, 'friendica_owner' => api_get_user($a, $self[0]['nurl']), - 'profiles' => $profiles); - return api_format_data("friendica_profiles", $type, array('$result' => $result)); + 'profiles' => $profiles]; + return api_format_data("friendica_profiles", $type, ['$result' => $result]); } api_register_func('api/friendica/profile/show', 'api_friendica_profile_show', true, API_METHOD_GET); +/** + * Returns a list of saved searches. + * + * @see https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-saved_searches-list + * + * @param string $type Return format: json or xml + * + * @return string|array + */ +function api_saved_searches_list($type) +{ + $terms = dba::select('search', ['id', 'term'], ['uid' => local_user()]); + + $result = []; + while ($term = $terms->fetch()) { + $result[] = [ + 'created_at' => api_date(time()), + 'id' => intval($term['id']), + 'id_str' => $term['id'], + 'name' => $term['term'], + 'position' => null, + 'query' => $term['term'] + ]; + } + + dba::close($terms); + + return api_format_data("terms", $type, ['terms' => $result]); +} + +/// @TODO move to top of file or somewhere better +api_register_func('api/saved_searches/list', 'api_saved_searches_list', true); + /* @TODO Maybe open to implement? To.Do: - [pagename] => api/1.1/statuses/lookup.json - [id] => 605138389168451584 - [include_cards] => true - [cards_platform] => Android-12 - [include_entities] => true - [include_my_retweet] => 1 - [include_rts] => 1 - [include_reply_count] => true - [include_descendent_reply_count] => true + [pagename] => api/1.1/statuses/lookup.json + [id] => 605138389168451584 + [include_cards] => true + [cards_platform] => Android-12 + [include_entities] => true + [include_my_retweet] => 1 + [include_rts] => 1 + [include_reply_count] => true + [include_descendent_reply_count] => true (?)