false, 'error' => ERR::REQ_METHOD, 'errhighlight' => -1, 'message' => 'Invalid request method (must be POST)']); $INPUT = array_merge($_GET, $_POST); if (!isset($INPUT['user_id'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_UID, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]']); if (!isset($INPUT['user_key'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_TOK, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]']); if (!isset($INPUT['title'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_TITLE, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]']); //------------------------------------------------------------------ $user_id = $INPUT['user_id']; $user_key = $INPUT['user_key']; $message = $INPUT['title']; $content = isset($INPUT['content']) ? $INPUT['content'] : ''; $priority = isset($INPUT['priority']) ? $INPUT['priority'] : '1'; $usrmsgid = isset($INPUT['msg_id']) ? $INPUT['msg_id'] : null; $time = isset($INPUT['timestamp']) ? $INPUT['timestamp'] : time(); //------------------------------------------------------------------ if (abs($time - time()) > 60*60*24*2) api_return(400, ['success' => false, 'error' => ERR::TIMESTAMP_OUT_OF_RANGE, 'errhighlight' => -1, 'message' => 'The timestamp mus be within 24 hours of now()']); if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, ['success' => false, 'error' => ERR::INVALID_PRIO, 'errhighlight' => 105, 'message' => 'Invalid priority']); if (strlen(trim($message)) == 0) api_return(400, ['success' => false, 'error' => ERR::NO_TITLE, 'errhighlight' => 103, 'message' => 'No title specified']); if ($usrmsgid != null && strlen($usrmsgid) > 64) api_return(400, ['success' => false, 'error' => ERR::USR_MSG_ID_TOO_LONG, 'errhighlight' => -1, 'message' => 'MessageID too long (64 characters)']); //------------------------------------------------------------------ $pdo = getDatabase(); $stmt = $pdo->prepare('SELECT user_id, user_key, fcm_token, messages_sent, quota_today, is_pro, quota_day FROM users WHERE user_id = :uid LIMIT 1'); $stmt->execute(['uid' => $user_id]); $datas = $stmt->fetchAll(PDO::FETCH_ASSOC); if (count($datas)<=0) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']); $data = $datas[0]; if ($data === null) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']); if ($data['user_id'] !== (int)$user_id) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'UserID not found']); if ($data['user_key'] !== $user_key) api_return(401, ['success' => false, 'error' => ERR::USER_AUTH_FAILED, 'errhighlight' => 102, 'message' => 'Authentification failed']); //------------------------------------------------------------------ if (strlen($message) > 120) api_return(400, ['success' => false, 'error' => ERR::TITLE_TOO_LONG, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']); if (strlen($content) > Statics::contentlen_max($data['is_pro'])) api_return(400, ['success' => false, 'error' => ERR::CONTENT_TOO_LONG, 'errhighlight' => 104, 'message' => 'Content too long ('.strlen($content).' characters; max := '.Statics::contentlen_max($data['is_pro']).' characters)']); //------------------------------------------------------------------ $fcm = $data['fcm_token']; $new_quota = $data['quota_today'] + 1; if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1; if ($new_quota > Statics::quota_max($data['is_pro'])) api_return(403, ['success' => false, 'error' => ERR::QUOTA_REACHED, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')']); if ($fcm == null || $fcm == '' || $fcm == false) { api_return(412, ['success' => false, 'error' => ERR::NO_DEVICE_LINKED, 'errhighlight' => -1, 'message' => 'No device linked with this account']); } //------------------------------------------------------------------ if ($usrmsgid != null) { $stmt = $pdo->prepare('SELECT scn_message_id FROM messages WHERE sender_user_id=:uid AND usr_message_id IS NOT NULL AND usr_message_id=:umid LIMIT 1'); $stmt->execute(['uid' => $user_id, 'umid' => $usrmsgid]); if (count($stmt->fetchAll(PDO::FETCH_ASSOC))>0) { api_return(200, [ 'success' => true, 'message' => 'Message already sent', 'suppress_send' => true, 'response' => '', 'messagecount' => $data['messages_sent']+1, 'quota' => $data['quota_today'], 'is_pro' => $data['is_pro'], 'quota_max' => Statics::quota_max($data['is_pro']), ]); } } //------------------------------------------------------------------ $pdo->beginTransaction(); $stmt = $pdo->prepare('INSERT INTO messages (sender_user_id, title, content, priority, sendtime, fcm_message_id, usr_message_id) VALUES (:suid, :t, :c, :p, :ts, :fmid, :umid)'); $stmt->execute( [ 'suid' => $user_id, 't' => $message, 'c' => $content, 'p' => $priority, 'ts' => $time, 'fmid' => null, 'umid' => $usrmsgid, ]); $scn_msg_id = $pdo->lastInsertId(); $url = "https://fcm.googleapis.com/fcm/send"; $payload = json_encode( [ 'to' => $fcm, //'dry_run' => true, 'android' => [ 'priority' => 'high' ], //'notification' => //[ // 'title' => $message, // 'body' => $content, //], 'data' => [ 'title' => $message, 'body' => str_limit($content, 1900), 'trimmed' => (strlen($content) > 1900), 'priority' => $priority, 'timestamp' => $time, 'usr_msg_id' => $usrmsgid, 'scn_msg_id' => $scn_msg_id, ] ]); $header= [ 'Authorization' => 'key=' . getConfig()['firebase']['server_key'], 'Content-Type' => 'application/json', ]; try { $httpresult = sendPOST($url, $payload, $header); if (try_json($httpresult, ['success']) != 1) { reportError("FCM communication failed (success_1 <> true)\n\n".$httpresult); $pdo->rollBack(); api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_ERRORED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.']); } } catch (Exception $e) { reportError("FCM communication failed", $e); $pdo->rollBack(); api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_FAILED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]); } //------------------------------------------------------------------ $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid'); $stmt->execute(['uid' => $user_id, 'q' => $new_quota]); $stmt = $pdo->prepare('UPDATE messages SET fcm_message_id=:fmid WHERE scn_message_id=:smid'); $stmt->execute([ 'fmid' => try_json($httpresult, ['results', 0, 'message_id']), 'smid' => $scn_msg_id ]); $pdo->commit(); //------------------------------------------------------------------ api_return(200, [ 'success' => true, 'error' => ERR::NO_ERROR, 'errhighlight' => -1, 'message' => 'Message sent', 'suppress_send' => false, 'response' => $httpresult, 'messagecount' => $data['messages_sent']+1, 'quota' => $new_quota, 'is_pro' => $data['is_pro'], 'quota_max' => Statics::quota_max($data['is_pro']), 'scn_msg_id' => $scn_msg_id, ]); } catch (Exception $mex) { reportError("Root try-catch triggered", $mex); if ($pdo !== null && $pdo->inTransaction()) $pdo->rollBack(); api_return(500, ['success' => false, 'error' => ERR::INTERNAL_EXCEPTION, 'errhighlight' => -1, 'message' => 'PHP script threw exception.'."\n\n".'Exception: ' . $e->getMessage()]); }