Example #1
0
 public function delete($id)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 8) {
         $this->response(null, null, 401);
     }
     if (!is_numeric($id)) {
         $this->response(null, null, 400);
     }
     $db = new RazorDB();
     // delete page
     $db->connect("page");
     $db->delete_rows(array("column" => "id", "value" => (int) $id));
     $db->disconnect();
     // remove any page_content items
     $db->connect("page_content");
     $db->delete_rows(array("column" => "page_id", "value" => (int) $id));
     $db->disconnect();
     // remove any menu_items
     $db->connect("menu_item");
     $db->delete_rows(array("column" => "page_id", "value" => (int) $id));
     $db->disconnect();
     // return the basic user details
     $this->response("success", "json");
 }
Example #2
0
 public function get($id)
 {
     $db = new RazorDB();
     $db->connect("content");
     // set options
     $options = array("order" => array("column" => "id", "direction" => "desc"));
     $search = array("column" => "id", "value" => null, "not" => true);
     $content = $db->get_rows($search, $options);
     $content = $content["result"];
     $db->disconnect();
     // now get all page content so we can show what pages are using this content
     $db->connect("page_content");
     $options = array("join" => array("table" => "page", "join_to" => "page_id"));
     $search = array("column" => "id", "value" => null, "not" => true);
     $page_content = $db->get_rows($search, $options);
     $page_content = $page_content["result"];
     $db->disconnect();
     foreach ($content as $key => $row) {
         foreach ($page_content as $pc) {
             if ($row["id"] == $pc["content_id"]) {
                 if (!isset($content[$key]["used_on_pages"])) {
                     $content[$key]["used_on_pages"] = array();
                 }
                 $content[$key]["used_on_pages"][$pc["page_id"]] = array("id" => $pc["page_id"], "name" => $pc["page_id.name"], "link" => $pc["page_id.link"]);
             }
         }
     }
     // return the basic user details
     $this->response(array("content" => $content), "json");
 }
Example #3
0
    public function post($data)
    {
        // no email
        if (empty($data["email"])) {
            $this->response("User not found", "json", 404);
        }
        // try find user
        $db = new RazorDB();
        $db->connect("user");
        $options = array("amount" => 1);
        $search = array("column" => "email_address", "value" => $data["email"]);
        $user = $db->get_rows($search);
        $db->disconnect();
        // check for match
        if ($user["count"] != 1) {
            $this->response("User not found", "json", 404);
        }
        // check attempts
        $user = $user["result"][0];
        if ($user["reminder_time"] > time() - 600) {
            $this->response("Only one password request allowed per hour", "json", 401);
        }
        /* Match found, attempts good, carry on */
        // now we will store token and send it via email
        $user_agent = $_SERVER["HTTP_USER_AGENT"];
        $ip_address = $_SERVER["REMOTE_ADDR"];
        $pass_hash = $user["password"];
        $reminder_time = time();
        $reminder_token = sha1($reminder_time . $user_agent . $ip_address . $pass_hash);
        // set new reminder
        $db->connect("user");
        $search = array("column" => "id", "value" => $user["id"]);
        $row = array("reminder_token" => $reminder_token, "reminder_time" => $reminder_time);
        $db->edit_rows($search, $row);
        $db->disconnect();
        // email user pasword reset email
        $server_email = str_replace("www.", "", $_SERVER["SERVER_NAME"]);
        $reminder_link = RAZOR_BASE_URL . "admin#/password-reset/{$reminder_token}_{$user["id"]}";
        $message = <<<EOT
<html>
<head>
    <title>razorCMS - Password Reset</title>
</head>
<body>
    <h1>Reset your razorCMS Account Password</h1>
    <p>This email address has requested a password reset for the account on razorCMS ({$_SERVER["SERVER_NAME"]}). If this was not you that requested this, please ignore this email and the password reset will expire in 1 hour.</p>
    <p>If you did request this, then you can reset your password using the link below.</p>
    <a href="{$reminder_link}">{$reminder_link}</a>
</body>
</html>
EOT;
        $this->email("no-reply@{$server_email}", $user["email_address"], "razorCMS Account Password Reset", $message);
        $this->response("success", "json");
    }
Example #4
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 6) {
         $this->response(null, null, 401);
     }
     if (empty($data)) {
         $this->response(null, null, 400);
     }
     $db = new RazorDB();
     $db->connect("page");
     // check link unique
     $options = array("amount" => 1);
     $search = array("column" => "link", "value" => isset($data["link"]) ? $data["link"] : "");
     $count = $db->get_rows($search, $options);
     if ($count["count"] > 0) {
         $this->response(array("error" => "duplicate link found", "code" => 101), 'json', 409);
     }
     // copy the page
     $row = array("name" => $data["name"], "title" => $data["title"], "link" => $data["link"], "keywords" => $data["keywords"], "description" => $data["description"], "access_level" => (int) $data["access_level"], "theme" => $data["theme"], "json_settings" => $data["json_settings"], "active" => false);
     $new_page = $db->add_rows($row);
     $db->disconnect();
     if ($new_page["count"] != 1) {
         $this->response(null, null, 400);
     }
     // next lets get all the page content for page we are copying
     $db->connect("page_content");
     $search = array("column" => "page_id", "value" => $data["id"]);
     $page_content = $db->get_rows($search);
     // now copy if any found
     if ($page_content["count"] > 0) {
         $new_rows = array();
         foreach ($page_content["result"] as $row) {
             $new_row = array();
             foreach ($row as $key => $col) {
                 if ($key == "id") {
                     continue;
                 } else {
                     if ($key == "page_id") {
                         $new_row[$key] = $new_page["result"][0]["id"];
                     } else {
                         $new_row[$key] = $col;
                     }
                 }
             }
             $new_rows[] = $new_row;
         }
         $db->add_rows($new_rows);
     }
     $db->disconnect();
     // return the basic page details
     $this->response($new_page["result"][0], "json");
 }
Example #5
0
 public function post($data)
 {
     // no email
     if (empty($data["email"])) {
         $this->response("User not found", "json", 404);
     }
     // try find user
     $db = new RazorDB();
     $db->connect("user");
     $options = array("amount" => 1);
     $search = array("column" => "email_address", "value" => $data["email"]);
     $user = $db->get_rows($search);
     $db->disconnect();
     // check for match
     if ($user["count"] != 1) {
         $this->response("User not found", "json", 404);
     }
     // check attempts
     $user = $user["result"][0];
     if ($user["reminder_time"] > time() - 600) {
         $this->response("Only one password request allowed per hour", "json", 401);
     }
     /* Match found, attempts good, carry on */
     // now we will store token and send it via email
     $user_agent = $_SERVER["HTTP_USER_AGENT"];
     $ip_address = $_SERVER["REMOTE_ADDR"];
     $pass_hash = $user["password"];
     $reminder_time = time();
     $reminder_token = sha1($reminder_time . $user_agent . $ip_address . $pass_hash);
     // set new reminder
     $db->connect("user");
     $search = array("column" => "id", "value" => $user["id"]);
     $row = array("reminder_token" => $reminder_token, "reminder_time" => $reminder_time);
     $db->edit_rows($search, $row);
     $db->disconnect();
     // get setting
     $db->connect("setting");
     $setting = $db->get_rows(array("column" => "name", "value" => "forgot_password_email"));
     $forgot_password_email = $setting["result"][0]["value"];
     $db->disconnect();
     // email user pasword reset email
     $server_email = str_replace("www.", "", $_SERVER["SERVER_NAME"]);
     $reminder_link = RAZOR_BASE_URL . "login#/password-reset/{$reminder_token}_{$user["id"]}";
     // email text replacement
     $search = array("**server_name**", "**user_email**", "**forgot_password_link**");
     $replace = array($_SERVER["SERVER_NAME"], $user["email_address"], $reminder_link);
     $message = str_replace($search, $replace, $forgot_password_email);
     $this->email("no-reply@{$server_email}", $user["email_address"], "{$_SERVER["SERVER_NAME"]} Account Password Reset", $message);
     $this->response("success", "json");
 }
Example #6
0
 public function post($ext)
 {
     if ((int) $this->check_access() < 9) {
         $this->response(null, null, 401);
     }
     if (empty($ext)) {
         $this->response(null, null, 400);
     }
     $settings = array();
     foreach ($ext["settings"] as $set) {
         $settings[$set["name"]] = $set["value"];
     }
     $db = new RazorDB();
     $db->connect("extension");
     $options = array("amount" => 1);
     $search = array(array("column" => "extension", "value" => $ext["extension"]), array("column" => "type", "value" => $ext["type"]), array("column" => "handle", "value" => $ext["handle"]));
     $extension = $db->get_rows($search, $options);
     if ($extension["count"] == 1) {
         $db->edit_rows($search, array("json_settings" => json_encode($settings)));
     } else {
         // add new
         $row = array("extension" => $ext["extension"], "type" => $ext["type"], "handle" => $ext["handle"], "json_settings" => json_encode($settings), "user_id" => $this->user["id"], "access_level" => 0);
         $db->add_rows($row);
     }
     $db->disconnect();
     $this->response("success", "json");
 }
Example #7
0
 public function get($id)
 {
     if ((int) $this->check_access() < 6) {
         $this->response(null, null, 401);
     }
     $db = new RazorDB();
     // get menu data too
     $db->connect("setting");
     $res = $db->get_rows(array("column" => "id", "value" => null, "not" => true));
     $db->disconnect();
     $settings = array();
     foreach ($res["result"] as $result) {
         switch ($result["type"]) {
             case "bool":
                 $settings[$result["name"]] = (bool) $result["value"];
                 break;
             case "int":
                 $settings[$result["name"]] = (int) $result["value"];
                 break;
             default:
                 $settings[$result["name"]] = (string) $result["value"];
                 break;
         }
     }
     // return the basic user details
     $this->response(array("settings" => $settings), "json");
 }
Example #8
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     if (empty($data)) {
         $this->response(null, null, 400);
     }
     $db = new RazorDB();
     $db->connect("user");
     // check link unique
     $search = array("column" => "id", "value" => $this->user["id"]);
     $row = array("name" => $data["name"], "email_address" => $data["email_address"]);
     if (isset($data["new_password"])) {
         $row["password"] = $this->create_hash($data["new_password"]);
     }
     $db->edit_rows($search, $row);
     $db->disconnect();
     // return the basic user details
     if (isset($data["new_password"])) {
         $this->response(array("reload" => true), "json");
     }
     $this->response("success", "json");
 }
Example #9
0
 public function post($data)
 {
     // check present, token ok, password and password confirm ok
     if (!isset($data["token"], $data["passwords"]["password"], $data["passwords"]["repeat_password"])) {
         $this->response("Bad data", null, 400);
     }
     if (empty($data["token"]) || strlen($data["token"]) < 20) {
         $this->response("Bad data", null, 400);
     }
     if (empty($data["passwords"]["password"]) || empty($data["passwords"]["repeat_password"]) || $data["passwords"]["password"] !== $data["passwords"]["repeat_password"]) {
         $this->response("Bad data", null, 400);
     }
     $token_data = explode("_", $data["token"]);
     if (count($token_data) != 2 || empty($token_data[0]) || empty($token_data[1])) {
         $this->response("Bad data", null, 400);
     }
     /* data present and pre check good, lets do a user search and check */
     // try find user
     $db = new RazorDB();
     $db->connect("user");
     $search = array("column" => "id", "value" => (int) $token_data[1]);
     $user = $db->get_rows($search);
     $db->disconnect();
     // no valid user found
     if ($user["count"] != 1) {
         $this->response("Bad data", null, 400);
     }
     $user = $user["result"][0];
     // check token
     if (empty($user["reminder_token"]) || $token_data[0] != $user["reminder_token"] || $user["reminder_time"] + 3600 < time()) {
         $this->response("Bad data", null, 400);
     }
     /* user ok, token ok, lets change password */
     $password = RazorAPI::create_hash($data["passwords"]["password"]);
     // set new reminder
     $db->connect("user");
     $search = array("column" => "id", "value" => $user["id"]);
     $row = array("password" => $password, "reminder_token" => "");
     $db->edit_rows($search, $row);
     $db->disconnect();
     $this->response("success", "json");
 }
Example #10
0
 public function get($id)
 {
     $db = new RazorDB();
     $db->connect("page");
     $search = array("column" => "id", "value" => null, "not" => true);
     $pages = $db->get_rows($search);
     $pages = $pages["result"];
     $db->disconnect();
     // return the basic user details
     $this->response(array("pages" => $pages), "json");
 }
Example #11
0
 public function get($page_id)
 {
     $db = new RazorDB();
     // get menu data too
     $db->connect("site");
     $search = array("column" => "id", "value" => 1);
     $site = $db->get_rows($search);
     $site = $site["result"][0];
     $db->disconnect();
     // return the basic user details
     $this->response(array("site" => $site), "json");
 }
Example #12
0
 public function get($id)
 {
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     $db = new RazorDB();
     $db->connect("user");
     // set options
     $options = array("filter" => array("id", "name", "email_address", "access_level", "active", "ip_address", "last_logged_in"));
     $search = array("column" => "id", "value" => null, "not" => true);
     $user = $db->get_rows($search, $options);
     $db->disconnect();
     // return the basic user details
     $this->response(array("users" => $user["result"]), "json");
 }
Example #13
0
 public function get($id)
 {
     if ((int) $this->check_access() < 6) {
         $this->response(null, null, 401);
     }
     if (empty($id)) {
         $this->response(null, null, 400);
     }
     // get menu data too
     $db = new RazorDB();
     $db->connect("system");
     $search = array("column" => "id", "value" => 1);
     $system = $db->get_rows($search);
     $system = $system["result"][0];
     $db->disconnect();
     $this->response(array("system" => $system), "json");
 }
Example #14
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     if (empty($data)) {
         $this->response(null, null, 400);
     }
     // update content
     $db = new RazorDB();
     $db->connect("page");
     // set options
     $search = array("column" => "id", "value" => $data["id"]);
     // ensure we only have changes we want
     $changes = array("active" => $data["active"], "name" => $data["name"], "title" => $data["title"], "link" => $data["link"], "theme" => $data["theme"], "keywords" => $data["keywords"], "description" => $data["description"]);
     $db->edit_rows($search, $changes);
     $db->disconnect();
     // return the basic user details
     $this->response($data, "json");
 }
Example #15
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     if (empty($data)) {
         $this->response(null, null, 400);
     }
     $db = new RazorDB();
     $db->connect("site");
     $search = array("column" => "id", "value" => 1);
     $row = array();
     if (isset($data["name"])) {
         $row["name"] = $data["name"];
     }
     if (isset($data["google_analytics_code"])) {
         $row["google_analytics_code"] = $data["google_analytics_code"];
     }
     $db->edit_rows($search, $row);
     $db->disconnect();
     $this->response("success", "json");
 }
Example #16
0
 public function get($id)
 {
     if (strlen($id) < 20) {
         $this->response("Activation key not set", 400);
     }
     $db = new RazorDB();
     $db->connect("user");
     $search = array("column" => "activate_token", "value" => $id);
     $user = $db->get_rows($search);
     if ($user["count"] != 1) {
         $this->response(null, null, 409);
     }
     // now we know token is ok, lets activate user
     // set new reminder
     $search = array("column" => "id", "value" => $user["result"][0]["id"]);
     $row = array("activate_token" => null, "active" => true);
     $db->edit_rows($search, $row);
     $db->disconnect();
     // if all ok, redirect to login page and set activate message off
     $redirect = RAZOR_BASE_URL . "login#/user-activated";
     header("Location: {$redirect}");
     exit;
 }
Example #17
0
 public function check_access($access_timeout = RARS_ACCESS_TIMEOUT)
 {
     // retrieve token from incoming request
     $token = isset($_SERVER["HTTP_AUTHORIZATION"]) ? $_SERVER["HTTP_AUTHORIZATION"] : (isset($_SERVER["REDIRECT_HTTP_AUTHORIZATION"]) ? $_SERVER["REDIRECT_HTTP_AUTHORIZATION"] : (isset($_COOKIE["token"]) ? $_COOKIE["token"] : null));
     if (empty($token)) {
         return false;
     }
     // extract token and id
     $token_data = explode("_", $token);
     if (count($token_data) != 2) {
         return false;
     }
     $token = preg_replace("/[^a-zA-Z0-9]/", '', $token_data[0]);
     $id = (int) $token_data[1];
     // find user
     $db = new RazorDB();
     $db->connect("user");
     $search = array("column" => "id", "value" => $id);
     $options = array("amount" => 1);
     $res = $db->get_rows($search, $options);
     $db->disconnect();
     // no user found or no access in XXX seconds
     if ($res["count"] != 1) {
         return false;
     }
     $user = $res["result"][0];
     if ($user["last_accessed"] < time() - $access_timeout) {
         return false;
     }
     /* all ok, so go verify user */
     // need to create a token and last logged stamp
     $last_logged = $user["last_logged_in"];
     $user_agent = preg_replace("/[^0-9a-zA-Z.:;-_]/", '', substr($_SERVER["HTTP_USER_AGENT"], 0, 250));
     $ip_address = preg_replace("/[^0-9.]/", '', substr($_SERVER["REMOTE_ADDR"], 0, 50));
     $pass_hash = $user["password"];
     $gen_token = sha1($last_logged . $user_agent . $ip_address . $pass_hash);
     if ($gen_token !== $token) {
         return false;
     }
     // set user and return
     $this->user = array("id" => $user["id"], "name" => $user["name"], "email_address" => $user["email_address"], "last_logged_in" => $user["last_logged_in"], "access_level" => $user["access_level"]);
     // update access time to keep connection alive, only do this once an hour to keep writes to db down for user table
     // connection will stay live for a day anyway so we do not need to be this heavy on the last access time writes
     if ($user["last_accessed"] > time() - 3600) {
         return $this->user["access_level"];
     }
     $db = new RazorDB();
     $db->connect("user");
     $search = array("column" => "id", "value" => $this->user["id"]);
     $changes = array("last_accessed" => time());
     $db->edit_rows($search, $changes);
     $db->disconnect();
     return $this->user["access_level"];
 }
Example #18
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     if (!isset($data["content"])) {
         $this->response(null, null, 400);
     }
     // update content
     $db = new RazorDB();
     $db->connect("content");
     // update or add content
     $new_content_map = array();
     foreach ($data["content"] as $key => $content) {
         if (!isset($content["content_id"]) || !isset($content["content"]) || empty($content["content"])) {
             unset($data["content"][$key]);
             continue;
         }
         if (stripos($content["content_id"], "new-") === false) {
             // update
             $search = array("column" => "id", "value" => $content["content_id"]);
             $db->edit_rows($search, array("content" => $content["content"], "name" => $content["name"]));
         } else {
             // add new content and map the ID to the new id for locations table
             $row = array("content" => $content["content"], "name" => $content["name"]);
             $result = $db->add_rows($row);
             $new_content_map[$content["content_id"]] = $result["result"][0]["id"];
         }
     }
     $db->disconnect();
     // update or add locations
     $db = new RazorDB();
     $db->connect("page_content");
     // 1. first take snapshot of current
     $search = array("column" => "page_id", "value" => (int) $data["page_id"]);
     $current_page_content = $db->get_rows($search);
     $current_page_content = $current_page_content["result"];
     // 2. iterate through updating or adding, make a note of all id's
     $page_content_map = array();
     foreach ($data["locations"] as $location => $columns) {
         foreach ($columns as $column => $blocks) {
             foreach ($blocks as $pos => $block) {
                 if ($block["id"] != "new") {
                     // update
                     $search = array("column" => "id", "value" => $block["id"]);
                     $row = array("location" => $location, "column" => (int) $column, "position" => $pos + 1, "json_settings" => json_encode($block["settings"]));
                     if (isset($block["extension"])) {
                         $row["extension"] = $block["extension"];
                     }
                     $db->edit_rows($search, $row);
                     $page_content_map[] = $block["id"];
                 } else {
                     // add new, if new, add, if new but already present add, else add as ext
                     $new_content_id = isset($block["content_id"], $new_content_map[$block["content_id"]]) ? $new_content_map[$block["content_id"]] : (isset($block["content_id"]) && is_numeric($block["content_id"]) ? $block["content_id"] : null);
                     if (!empty($new_content_id) || isset($block["extension"])) {
                         $row = array("page_id" => (int) $data["page_id"], "content_id" => $new_content_id, "location" => $location, "column" => (int) $column, "position" => $pos + 1);
                         if (isset($block["extension"])) {
                             $row["extension"] = $block["extension"];
                             $row["json_settings"] = isset($block["settings"]) ? json_encode($block["settings"]) : null;
                         }
                         $result = $db->add_rows($row);
                         $page_content_map[] = $result["result"][0];
                     }
                 }
             }
         }
     }
     // 3. run through id's affected against snapshot, if any missing, remove them.
     foreach ($current_page_content as $row) {
         if (!in_array($row["id"], $page_content_map)) {
             $db->delete_rows(array("column" => "id", "value" => (int) $row["id"]));
         }
     }
     $db->disconnect();
     // return the basic user details
     $this->response("success", "json");
 }
Example #19
0
 public function get($type)
 {
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     if (empty($type) || !in_array($type, $this->types)) {
         $this->response(null, null, 400);
     }
     // first scan the folders for manifests
     $manifests = RazorFileTools::find_file_contents(RAZOR_BASE_PATH . "extension", "manifest.json", "json", "end");
     // split into types, so we can filter a little
     $extensions = array();
     $db = new RazorDB();
     $db->connect("extension");
     foreach ($manifests as $mf) {
         $mf->created = date("D jS M Y", $mf->created);
         // grab settings if any
         if (isset($mf->settings)) {
             $options = array("amount" => 1);
             $search = array(array("column" => "extension", "value" => $mf->extension), array("column" => "type", "value" => $mf->type), array("column" => "handle", "value" => $mf->handle));
             $extension = $db->get_rows($search, $options);
             if ($extension["count"] == 1) {
                 $db_settings = json_decode($extension["result"][0]["json_settings"]);
                 foreach ($mf->settings as $key => $setting) {
                     if (isset($db_settings->{$setting->name})) {
                         $mf->settings[$key]->value = $db_settings->{$setting->name};
                     }
                 }
             }
         }
         // sort list
         if ($mf->type == $type) {
             if ($mf->type == "theme") {
                 // group manifest layouts for themes
                 if (!isset($extensions[$mf->type . $mf->handle . $mf->extension])) {
                     $extensions[$mf->type . $mf->handle . $mf->extension] = array("layouts" => array(), "type" => $mf->type, "handle" => $mf->handle, "description" => $mf->description, "name" => $mf->name);
                 }
                 $extensions[$mf->type . $mf->handle . $mf->extension]["layouts"][] = $mf;
             } else {
                 $extensions[] = $mf;
             }
         } else {
             if ($type == "system" && $mf->type != "theme") {
                 $extensions[] = $mf;
             } else {
                 if ($type == "all") {
                     $mf->type = ucfirst($mf->type);
                     if ($mf->type == "Theme") {
                         // group manifest layouts for themes
                         if (!isset($extensions[$mf->type . $mf->handle . $mf->extension])) {
                             $extensions[$mf->type . $mf->handle . $mf->extension] = array("layouts" => array(), "type" => $mf->type, "handle" => $mf->handle, "extension" => $mf->extension, "description" => $mf->description, "name" => $mf->name);
                         }
                         $extensions[$mf->type . $mf->handle . $mf->extension]["layouts"][] = $mf;
                     } else {
                         $extensions[] = $mf;
                     }
                 }
             }
         }
     }
     // ensure we have array return and not object
     $extensions = array_values($extensions);
     $db->disconnect();
     $this->response(array("extensions" => $extensions), "json");
 }
Example #20
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 10) {
         $this->response(null, null, 401);
     }
     // menu item
     $db = new RazorDB();
     $db->connect("menu_item");
     // 1. grab all menus in position order
     $options = array("order" => array("column" => "position", "direction" => "asc"));
     $search = array("column" => "id", "not" => true, "value" => null);
     $all_menu_items = $db->get_rows($search, $options);
     $all_menu_items = $all_menu_items["result"];
     // 2. make flat arrays
     $new_menus_flat = array();
     foreach ($data as $menu) {
         // set up menu item arrays
         if (!isset($new_menus_flat[$menu["id"]])) {
             $new_menus_flat[$menu["id"]] = array();
         }
         foreach ($menu["menu_items"] as $mi) {
             if (isset($mi["id"])) {
                 $new_menus_flat[$menu["id"]][] = $mi["id"];
             }
             if (isset($mi["sub_menu"]) & !empty($mi["sub_menu"])) {
                 foreach ($mi["sub_menu"] as $sub_menu_item) {
                     if (isset($sub_menu_item["id"])) {
                         $new_menus_flat[$menu["id"]][] = $sub_menu_item["id"];
                     }
                 }
             }
         }
     }
     $current_menus_flat = array();
     foreach ($all_menu_items as $ami) {
         // set up menu item arrays
         if (!isset($current_menus_flat[$ami["menu_id"]])) {
             $current_menus_flat[$ami["menu_id"]] = array();
         }
         $current_menus_flat[$ami["menu_id"]][] = $ami["id"];
         // at same time remove any items missing
         if (!in_array($ami["id"], $new_menus_flat[$ami["menu_id"]])) {
             $db->delete_rows(array("column" => "id", "value" => (int) $ami["id"]));
         }
     }
     // 3. update all of sent menu data, by looping through the new $data
     foreach ($data as $new_menu) {
         $pos = 1;
         // each menu
         foreach ($new_menu["menu_items"] as $nmi) {
             if (isset($nmi["id"]) && in_array($nmi["id"], $current_menus_flat[$new_menu["id"]])) {
                 // update menu item
                 $search = array("column" => "id", "value" => $nmi["id"]);
                 $db->edit_rows($search, array("position" => $pos));
             } else {
                 // add new item
                 $row = array("menu_id" => (int) $new_menu["id"], "position" => $pos, "level" => 1, "page_id" => $nmi["page_id"], "link_id" => 0);
                 $db->add_rows($row);
             }
             $pos++;
             // now check for sub menu
             if (isset($nmi["sub_menu"]) && !empty($nmi["sub_menu"])) {
                 foreach ($nmi["sub_menu"] as $nsmi) {
                     if (isset($nsmi["id"]) && in_array($nsmi["id"], $current_menus_flat[$new_menu["id"]])) {
                         // update menu item
                         $search = array("column" => "id", "value" => $nsmi["id"]);
                         $db->edit_rows($search, array("position" => $pos));
                     } else {
                         // add new item
                         $row = array("menu_id" => (int) $new_menu["id"], "position" => $pos, "level" => 2, "page_id" => $nsmi["page_id"], "link_id" => 0);
                         $db->add_rows($row);
                     }
                     $pos++;
                 }
             }
         }
     }
     $db->disconnect();
     $this->response("success", "json");
 }
Example #21
0
 private function get_content_data()
 {
     // if no page found, end here
     if (empty($this->page)) {
         return;
     }
     // grab all content
     $db = new RazorDB();
     $db->connect("page_content");
     // set options
     $options = array("order" => array("column" => "position", "direction" => "asc"));
     $search = array("column" => "page_id", "value" => $this->page["id"]);
     $content = $db->get_rows($search, $options);
     $this->content = $content["result"];
     $db->disconnect();
 }
Example #22
0
 /**
  * Get rows from search
  *
  * Fetch all the rows found from a search on a columns
  * Using extra parameters you can specify, not, wildcard, case insensitive as well as specify how to use one search with another (default is or)
  * @param array $search Search [column => string, value => mixed[, not => bool, and => bool, case_insensitive => bool, wildcard => bool]]
  * @param array $options Any options to use ['filter': array['col1', 'col2'...], 'amount': int, 'join': array['table' => string, 'join_to' => string]] multiple joins can be added to array, all joins are inner
  * @return mixed The data in array format ('table' => 'name, 'count' => resultCount, 'result' => rows(('col' => 'val',...)) or false on fail
  */
 public function get_rows($search, $options = null)
 {
     // check connected
     if (!$this->connected) {
         trigger_error("Not connected to table, cannot perform query");
         return false;
     }
     // resolve table name and file
     $time = microtime(true);
     // options
     $amount = isset($options['amount']) ? $options['amount'] : null;
     $filter = isset($options['filter']) ? $options['filter'] : null;
     $joins = isset($options['join']) ? $options['join'] : null;
     $order = isset($options['order']) ? $options['order'] : null;
     // get table headers
     if (empty($this->columns)) {
         if (!$this->headers()) {
             return false;
         }
     }
     // check for single or multi array
     if (isset($search['column'])) {
         $search = array($search);
     }
     foreach ($search as $search_data) {
         if (!isset($search_data['column'])) {
             trigger_error("'column' not provided in search");
             return false;
         }
         if (!isset($this->columns[$search_data['column']])) {
             trigger_error("Column '{$search_data['column']}' does not exist in table '{$this->table}'");
             return false;
         }
     }
     // resolve join data
     if ($joins !== null) {
         if (isset($joins['table'])) {
             $joins = array($joins);
         }
         foreach ($joins as $join_data) {
             // check all join data present
             if (!isset($join_data['table']) || !isset($join_data['join_to'])) {
                 trigger_error("Join needs 'table', 'join_to' in order to join a table");
                 return false;
             }
             // check join table exists
             if (!is_file(RAZOR_BASE_PATH . "storage/database/{$join_data['table']}.db.php")) {
                 // return error on non bad con
                 trigger_error("Cannot join table '{$join_data['table']}', table does not exist");
                 return false;
             }
             // check join_to column exists in parent table
             if (!isset($this->columns[$join_data['join_to']])) {
                 trigger_error("Cannot join to column '{$join_data['join_to']}' in parent table '{$this->table}', column does not exist");
                 return false;
             }
         }
     }
     // open and move pointer to beginning
     $this->open();
     // work out how many markers to use and size (16ms without prequery on test3)
     $markers_amount = (int) round($this->row_count / 150);
     if ($markers_amount < 1) {
         $markers_amount = 1;
     }
     fseek($this->handle, 0, SEEK_END);
     $size = ftell($this->handle);
     $marker_size = round($size / $markers_amount);
     fseek($this->handle, 0, SEEK_SET);
     // perform query
     $matches = array();
     $cpq = 0;
     // skip headers
     stream_get_line($this->handle, 2048, "--- end headers ---\n");
     while (!feof($this->handle)) {
         // read in block, if not first, clean up to first \n
         $pq_cache = stream_get_line($this->handle, $marker_size);
         if ($cpq > 0) {
             if (($find_me = strpos($pq_cache, "\n")) === false) {
                 break;
             }
             // no more complete lines left
             $pq_cache = substr($pq_cache, $find_me + 1);
             // clean up to first \n
         }
         $cpq++;
         // cache file pointer
         $pre_query_position = ftell($this->handle);
         // read in to next \n to finish line off (at least a meg)
         $pq_cache .= stream_get_line($this->handle, 1049000, "\n");
         // rewind file pointer
         fseek($this->handle, $pre_query_position, SEEK_SET);
         // send pq cache off for pre-query
         if ($this->pre_query($pq_cache, $search) !== false) {
             // if match, iterate over $pq_cache, maybe explode it by \n and query each value
             $rows = explode("\n", $pq_cache);
             foreach ($rows as $row_data) {
                 // Check row data
                 if (substr($row_data, 3, 4) !== 'row:') {
                     trigger_error("Failed to read line in '{$this->table}' db file, db file corrupt");
                     return false;
                 }
                 // query further
                 $match = $this->query($row_data, $search, true);
                 // filter
                 if (!empty($match)) {
                     // collate join data for search later
                     if ($joins !== null) {
                         $j = 0;
                         foreach ($joins as $join) {
                             $joins[$j]['join_data'][$match[$join['join_to']]] = array('column' => 'id', 'value' => $match[$join['join_to']]);
                             $j++;
                         }
                     }
                     // filter out any cols do not want in results
                     if (!empty($filter)) {
                         foreach ($match as $match_col => $match_value) {
                             if (is_string($filter) && $match_col !== $filter || is_array($filter) && !in_array($match_col, $filter)) {
                                 unset($match[$match_col]);
                             }
                         }
                     }
                     $matches[] = $match;
                 }
                 // collect correct amount of rows
                 if ($amount !== null && count($matches) >= $amount) {
                     $result = array('table' => $this->table, 'count' => count($matches), 'time' => microtime(true) - $time, 'result' => $matches);
                     return $result;
                 }
             }
         }
     }
     $this->close();
     // perform any join searchs now
     if ($joins !== null) {
         foreach ($joins as $join) {
             $join_ob = new RazorDB('razor_db:join:' . $this->table . '>' . $join['table']);
             if (!$join_ob->connect($join['table'])) {
                 trigger_error("Failed to join table '{$join['table']}' omitting this data from results");
                 continue;
             }
             // no join data found, skip this join
             if (!isset($join['join_data'])) {
                 continue;
             }
             $found = $join_ob->get_rows($join['join_data']);
             // attach data to matches
             foreach ($matches as $key => $match) {
                 if ($found['count'] > 0) {
                     foreach ($found['result'] as $found_result) {
                         if ($match[$join['join_to']] === $found_result['id']) {
                             foreach ($found_result as $col => $val) {
                                 $matches[$key][$join['join_to'] . '.' . $col] = $val;
                             }
                         }
                     }
                 } else {
                     // no results so no match
                     unset($matches[$key]);
                 }
             }
             $join_ob->disconnect();
         }
     }
     // sort results
     if (!empty($order)) {
         $this->order = $order;
         usort($matches, array($this, 'sort'));
     }
     $result = array('table' => $this->table, 'count' => count($matches), 'time' => microtime(true) - $time, 'result' => $matches, 'order' => $order);
     return $result;
 }
Example #23
0
 public function post($data)
 {
     // are we accepting registrations
     $db = new RazorDB();
     // get menu data too
     $db->connect("setting");
     $allow = $db->get_rows(array("column" => "name", "value" => "allow_registration"));
     $manual = $db->get_rows(array("column" => "name", "value" => "manual_activation"));
     $registration_email = $db->get_rows(array("column" => "name", "value" => "registration_email"));
     $activation_email = $db->get_rows(array("column" => "name", "value" => "activation_email"));
     $activate_user_email = $db->get_rows(array("column" => "name", "value" => "activate_user_email"));
     $db->disconnect();
     if (!isset($allow["result"][0]["value"]) || !$allow["result"][0]["value"]) {
         $this->response(null, null, 405);
     }
     // verify form is coming from site and that human has sent it
     // Check details
     if (!isset($_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"], $_SERVER["HTTP_REFERER"], $_SESSION["signature"])) {
         $this->response(null, null, 400);
     }
     if (empty($_SERVER["REMOTE_ADDR"]) || empty($_SERVER["HTTP_USER_AGENT"]) || empty($_SERVER["HTTP_REFERER"]) || empty($_SESSION["signature"])) {
         $this->response(null, null, 400);
     }
     // check referer matches the site
     if (strpos($_SERVER["HTTP_REFERER"], RAZOR_BASE_URL) !== 0) {
         $this->response(null, null, 400);
     }
     // check data
     if (!isset($data["signature"], $data["name"], $data["email_address"], $data["new_password"])) {
         $this->response(null, null, 400);
     }
     if (empty($data["signature"]) || empty($data["name"]) || empty($data["email_address"]) || empty($data["new_password"])) {
         $this->response(null, null, 400);
     }
     if (!isset($data["human"]) || !empty($data["human"])) {
         $this->response("robot", "json", 406);
     }
     // get signature and compare to session
     if ($_SESSION["signature"] !== $data["signature"]) {
         $this->response(null, null, 400);
     }
     unset($_SESSION["signature"]);
     session_destroy();
     // now we know registrations allowed, form came from website etc so lets check email unique and proceed with adding user
     $db->connect("user");
     // check email is unique
     $search = array("column" => "email_address", "value" => $data["email_address"]);
     $user = $db->get_rows($search);
     if ($user["count"] > 0) {
         $this->response(null, null, 409);
     }
     // create new user
     $password = $this->create_hash($data["new_password"]);
     $row = array("name" => $data["name"], "email_address" => $data["email_address"], "access_level" => 1, "active" => false, "password" => $this->create_hash($data["new_password"]));
     $activate_link = "";
     if (!$manual["result"][0]["value"]) {
         $activate_token = sha1($_SERVER["HTTP_USER_AGENT"] . $_SERVER["REMOTE_ADDR"] . $password);
         $row["activate_token"] = $activate_token;
         $activate_link = RAZOR_BASE_URL . "rars/user/activate/{$activate_token}";
     }
     $db->add_rows($row);
     $db->disconnect();
     $server_email = str_replace("www.", "", $_SERVER["SERVER_NAME"]);
     // email text replacement
     $search = array("**server_name**", "**user_email**", "**activation_link**");
     $replace = array($_SERVER["SERVER_NAME"], $data["email_address"], $activate_link);
     if ($manual["result"][0]["value"]) {
         // send notifcation of registration and activation is manual to user
         $message1 = str_replace($search, $replace, $registration_email["result"][0]["value"]);
         $this->email("no-reply@{$server_email}", $data["email_address"], "{$_SERVER["SERVER_NAME"]} Account Registered", $message1);
         // send notifcation to super admin email that someone has registered and needs activation
         $db->connect("user");
         $res = $db->get_rows(array("column" => "id", "value" => 1));
         $super_email = $res["result"][0]["email_address"];
         $db->disconnect();
         $message2 = str_replace($search, $replace, $activate_user_email["result"][0]["value"]);
         $this->email("no-reply@{$server_email}", $super_email, "{$_SERVER["SERVER_NAME"]} Account Registered", $message2);
     } else {
         $message3 = str_replace($search, $replace, $activation_email["result"][0]["value"]);
         $this->email("no-reply@{$server_email}", $data["email_address"], "{$_SERVER["SERVER_NAME"]} Account Activation", $message3);
     }
     $this->response(array("manual_activation" => $manual["result"][0]["value"]), "json");
 }
Example #24
0
 public function delete($id)
 {
     // check we have a logged in user
     if ((int) $this->check_access() < 1) {
         $this->response(null, null, 401);
     }
     if (empty($id)) {
         $this->response(null, null, 400);
     }
     if ($id == 1) {
         $this->response(null, null, 400);
     }
     $id = (int) $id;
     $db = new RazorDB();
     $db->connect("user");
     if ($this->user["id"] == $id) {
         // this is your account, allow removal of own account
         $search = array("column" => "id", "value" => $this->user["id"]);
         $db->delete_rows($search);
         $response = "reload";
     } elseif ($this->check_access() == 10) {
         // if not account owner, but acces of 10, can remove account
         $search = array("column" => "id", "value" => $id);
         $db->delete_rows($search);
         $response = "success";
     } else {
         $this->response(null, null, 401);
     }
     $db->disconnect();
     $this->response($response, "json");
 }
Example #25
0
 public function post($data)
 {
     // login check - if fail, return no data to stop error flagging to user
     if ((int) $this->check_access() < 9) {
         $this->response(null, null, 401);
     }
     if (empty($data)) {
         $this->response(null, null, 400);
     }
     $db = new RazorDB();
     $db->connect("setting");
     if (isset($data["name"])) {
         $search = array("column" => "name", "value" => "name");
         $res = $db->edit_rows($search, array("value" => $data["name"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "name", "value" => (string) $data["name"], "type" => "string"));
         }
     }
     if (isset($data["google_analytics_code"])) {
         $search = array("column" => "name", "value" => "google_analytics_code");
         $res = $db->edit_rows($search, array("value" => $data["google_analytics_code"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "google_analytics_code", "value" => (string) $data["google_analytics_code"], "type" => "string"));
         }
     }
     if (isset($data["forgot_password_email"])) {
         $search = array("column" => "name", "value" => "forgot_password_email");
         $res = $db->edit_rows($search, array("value" => (string) $data["forgot_password_email"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "forgot_password_email", "value" => (string) $data["forgot_password_email"], "type" => "string"));
         }
     }
     if (isset($data["allow_registration"])) {
         $search = array("column" => "name", "value" => "allow_registration");
         $res = $db->edit_rows($search, array("value" => (string) $data["allow_registration"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "allow_registration", "value" => (string) $data["allow_registration"], "type" => "bool"));
         }
     }
     if (isset($data["manual_activation"])) {
         $search = array("column" => "name", "value" => "manual_activation");
         $res = $db->edit_rows($search, array("value" => (string) $data["manual_activation"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "manual_activation", "value" => (string) $data["manual_activation"], "type" => "bool"));
         }
     }
     if (isset($data["registration_email"])) {
         $search = array("column" => "name", "value" => "registration_email");
         $res = $db->edit_rows($search, array("value" => (string) $data["registration_email"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "registration_email", "value" => (string) $data["registration_email"], "type" => "string"));
         }
     }
     if (isset($data["activation_email"])) {
         $search = array("column" => "name", "value" => "activation_email");
         $res = $db->edit_rows($search, array("value" => (string) $data["activation_email"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "activation_email", "value" => (string) $data["activation_email"], "type" => "string"));
         }
     }
     if (isset($data["activate_user_email"])) {
         $search = array("column" => "name", "value" => "activate_user_email");
         $res = $db->edit_rows($search, array("value" => (string) $data["activate_user_email"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "activate_user_email", "value" => (string) $data["activate_user_email"], "type" => "string"));
         }
     }
     if (isset($data["cookie_message"])) {
         $search = array("column" => "name", "value" => "cookie_message");
         $res = $db->edit_rows($search, array("value" => (string) $data["cookie_message"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "cookie_message", "value" => (string) $data["cookie_message"], "type" => "string"));
         }
     }
     if (isset($data["cookie_message_button"])) {
         $search = array("column" => "name", "value" => "cookie_message_button");
         $res = $db->edit_rows($search, array("value" => (string) $data["cookie_message_button"]));
         if ($res["count"] == 0) {
             $db->add_rows(array("name" => "cookie_message_button", "value" => (string) $data["cookie_message_button"], "type" => "string"));
         }
     }
     $db->disconnect();
     $this->response("success", "json");
 }
Example #26
0
 public function post($data)
 {
     // Check details
     if (!isset($_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"], $_SERVER["HTTP_REFERER"], $_SESSION["signature"])) {
         $this->response(null, null, 400);
     }
     if (empty($_SERVER["REMOTE_ADDR"]) || empty($_SERVER["HTTP_USER_AGENT"]) || empty($_SERVER["HTTP_REFERER"]) || empty($_SESSION["signature"])) {
         $this->response(null, null, 400);
     }
     // check referer matches the site
     if (strpos($_SERVER["HTTP_REFERER"], RAZOR_BASE_URL) !== 0) {
         $this->response(null, null, 400);
     }
     // check data
     if (!isset($data["signature"], $data["email"], $data["message"], $data["extension"]["type"], $data["extension"]["handle"], $data["extension"]["extension"])) {
         $this->response(null, null, 400);
     }
     if (empty($data["signature"]) || empty($data["email"]) || empty($data["message"]) || empty($data["extension"]["type"]) || empty($data["extension"]["handle"]) || empty($data["extension"]["extension"])) {
         $this->response(null, null, 400);
     }
     if (!isset($data["human"]) || !empty($data["human"])) {
         $this->response("robot", "json", 406);
     }
     // get signature and compare to session
     if ($_SESSION["signature"] !== $data["signature"]) {
         $this->response(null, null, 400);
     }
     unset($_SESSION["signature"]);
     session_destroy();
     // create manifest path for extension that requested email
     $ext_type = preg_replace('/[^A-Za-z0-9-]/', '', $data["extension"]["type"]);
     $ext_handle = preg_replace('/[^A-Za-z0-9-]/', '', $data["extension"]["handle"]);
     $ext_extension = preg_replace('/[^A-Za-z0-9-]/', '', $data["extension"]["extension"]);
     $manifest_path = RAZOR_BASE_PATH . "extension/{$ext_type}/{$ext_handle}/{$ext_extension}/{$ext_extension}.manifest.json";
     if (!is_file($manifest_path)) {
         $this->response(null, null, 400);
     }
     $manifest = RazorFileTools::read_file_contents($manifest_path, "json");
     // fetch extension settings and look for email
     $db = new RazorDB();
     $db->connect("extension");
     $options = array("amount" => 1, "filter" => array("json_settings"));
     $search = array(array("column" => "type", "value" => $manifest->type), array("column" => "handle", "value" => $manifest->handle), array("column" => "extension", "value" => $manifest->extension));
     $extension_settings = $db->get_rows($search, $options);
     $extension_settings = $extension_settings["result"][0]["json_settings"];
     $db->disconnect();
     if (empty($extension_settings)) {
         $this->response(null, null, 400);
     }
     $extension_settings = json_decode($extension_settings);
     // get site data
     $db->connect("setting");
     $res = $db->get_rows(array("column" => "id", "value" => null, "not" => true));
     $db->disconnect();
     $settings = array();
     foreach ($res["result"] as $result) {
         switch ($result["type"]) {
             case "bool":
                 $settings[$result["name"]] = (bool) $result["value"];
                 break;
             case "int":
                 $settings[$result["name"]] = (int) $result["value"];
                 break;
             default:
                 $settings[$result["name"]] = (string) $result["value"];
                 break;
         }
     }
     // clean email data
     $to = $extension_settings->email;
     $from = preg_replace('/[^A-Za-z0-9-_+@.]/', '', $data["email"]);
     $subject = "{$settings["name"]} Contact Form";
     $message = htmlspecialchars($data["message"], ENT_QUOTES);
     // send to email response
     $this->email($from, $to, $subject, $message);
     // return the basic user details
     $this->response("success", "json");
 }
Example #27
0
 public function get($phrase)
 {
     if (empty($phrase)) {
         $this->response(null, null, 400);
     }
     // search database and use scoring system to order. need to do pagination somehow
     $db = new RazorDB();
     // first break the search data down into searchable chunks
     $words = explode(' ', $phrase);
     // find page ids matching query results
     $db->connect('page');
     $options = array('filter' => array('id'));
     $search = array();
     foreach ($words as $word) {
         $search[] = array('column' => 'title', 'value' => $word, 'case_insensitive' => true, 'wildcard' => true);
         $search[] = array('column' => 'description', 'value' => $word, 'case_insensitive' => true, 'wildcard' => true);
         $search[] = array('column' => 'keywords', 'value' => $word, 'case_insensitive' => true, 'wildcard' => true);
     }
     $pages = $db->get_rows($search);
     $db->disconnect();
     // find content ids matching query results
     $db->connect('content');
     $options = array('filter' => array('id'));
     $search = array();
     foreach ($words as $word) {
         $search[] = array('column' => 'content', 'value' => $word, 'case_insensitive' => true, 'wildcard' => true);
     }
     $content = $db->get_rows($search);
     $db->disconnect();
     // find page and content from IDs
     if ($content['count'] > 0 || $pages['count'] > 0) {
         $db->connect('page_content');
         $options = array('join' => array(array('table' => 'content', 'join_to' => 'content_id'), array('table' => 'page', 'join_to' => 'page_id')), 'filter' => array('id', 'page_id', 'content_id', 'page_id.title', 'page_id.description', 'page_id.keywords', 'content_id.content', 'page_id.link', 'page_id.name'));
         $search = array();
         foreach ($content['result'] as $row) {
             $search[] = array('column' => 'content_id', 'value' => $row['id']);
         }
         foreach ($pages['result'] as $row) {
             $search[] = array('column' => 'page_id', 'value' => $row['id']);
         }
         $page_content = $db->get_rows($search, $options);
         $db->disconnect();
     }
     if (!isset($page_content) || $page_content['count'] < 1) {
         $this->response(null, null, 404);
     }
     /* We now have a collection of all matches */
     // loop through results working out scoring, removing duplicates
     $matches = array();
     foreach ($page_content['result'] as $pc) {
         // capture page for results and set page score once
         if (!isset($matches[$pc['page_id']])) {
             $matches[$pc['page_id']] = $pc;
             $matches[$pc['page_id']]['score'] = $this->get_page_score($pc, $phrase);
         }
         // work out content score each content on page
         $matches[$pc['page_id']]['score'] += $this->get_content_score($pc, $phrase);
     }
     // present the results as an array sorted by score
     usort($matches, array('self', 'sort_score'));
     $this->response(array('results' => $matches), 'json');
 }