PHP exercise to read or write database values I just came up with the code below but I'm wondering if there is room for improvement? I.e. better readability and or performance, better structure, less lines of code?

The script should parse a simple HTTP GET or POST request. The request can contain the following parameters:


action (required, possible values are "read" and "write");
mykey (required)
id (only required when action equals "read")


Depending on a read or write request the script should print an array containing:


status;
id (only after writing / inserting a value into database);
value (in case of a read request);


Sample requests:


api.php?action=write&amp;mykey=12345&amp;value=im%20fine
api.php?action=read&amp;mykey=12345&amp;id=13


The script should also log the content of the request to file. (append)

Code:

&lt;?php
  include("opendb.php");
  $logging = true;
  $log = serialize($_REQUEST) . PHP_EOL;

  $reply = array("id" =&gt; null, "status" =&gt; null);

  if(isset($_REQUEST["action"]) &amp;&amp; isset($_REQUEST["mykey"])) {
    $action = strtolower($_REQUEST["action"]);
    $mykey = $mysqli-&gt;real_escape_string($_REQUEST["mykey"]);

    if($action == "read") {
      if(isset($_REQUEST["id"]) &amp;&amp; is_numeric($_REQUEST["id"])) {
        $id = $_REQUEST["id"];
        // read message from database
        $sql = "SELECT * FROM data WHERE mykey = '$mykey' AND id = $id";

        if ($result = $mysqli-&gt;query($sql)) {
            $row = $result-&gt;fetch_assoc();
            $reply["id"] = $id;
            $reply["value"] = $row["value"];
            $reply["status"] = "success";
        } else {
            $log .= $mysqli-&gt;error . PHP_EOL;
            $reply["status"] = "error";
        }
      } else {
          $log .= "id missing" . PHP_EOL;
          $reply["status"] = "error (incorrect id)";
      }
    } elseif($action == "write") {
      // write message to database
      $value = $mysqli-&gt;real_escape_string($_REQUEST["value"]);

      $sql = "INSERT INTO `data` (`value`, `mykey`) VALUES ('$value', '$mykey')";

      if ($result = $mysqli-&gt;query($sql)) {
          $reply["id"] = $mysqli-&gt;insert_id;
          $reply["status"] = "success";
      } else {
          $log .= $mysqli-&gt;error . PHP_EOL;
          $reply["status"] = "error";
      }
    }
  } else {
      $log .= "invalid querystring" . PHP_EOL;
      $reply["status"] = "error (incorrect action, mykey)";
  }

  print_r($reply);

  if($logging) {
    file_put_contents('log/read_write_exercise.log', date('d-m-Y') . " " . print_r($log, TRUE), FILE_APPEND | LOCK_EX) ;
  }
?&gt;
Instead of using a big stack of if/elseif, since you're just checking the value of a single variable you should be using a switch/case instead.
What if action and mykey are both set, but action is neither read nor write - Your user will get a blank response.. yet another reason to use a switch (with a default option).
Don't use real_escape_string, use prepared statements instead.
Don't SELECT * ... if you only need the value column, just select value ...
I would suggest creating a function to handle errors.
I would suggest holding your errors in an array and joining them rather than concatting to a string - this will be more efficient and manageable.
There is no reason to use LOCK_EX in conjunction with FILE_APPEND - If you lock the file and the script is called simultaneously one instance will be blocked or denied while the other is writing. See here for more info.
Is this not supposed to be an API? If it is you might consider outputting JSON instead of print_ring the results. I would suggest putting this in an output function as well.




include("opendb.php");
$logging = true;
$log = array(date('d-m-Y'));
$log[] = serialize($_REQUEST)

$reply = array("id" =&gt; null, "status" =&gt; 'success');

if(!isset($_REQUEST["mykey"])) error("No key provided.");
$action = empty($_REQUEST["action"]) ? "" : strtolower($_REQUEST["action"])

switch($action){

    case "read":
        if(!isset($_REQUEST["id"])) error('No ID provided.');
        $stmt = $mysqli-&gt;prepare("SELECT value FROM data WHERE mykey = ? AND id = ?");
        $stmt-&gt;bind_param('si', $_REQUEST["mykey"], $_REQUEST["id"]);
        $stmt-&gt;execute();
        $stmt-&gt;bind_result($value);
        if(!$stmt-&gt;fetch()) error("No results found.");
        $reply["id"] = $_REQUEST["id"];
        $reply["value"] = $value;
        output();

    case "write":
        if(!isset($_REQUEST["value"])) error('No value provided.');
        $stmt = $mysqli-&gt;prepare(INSERT INTO `data` (`value`, `mykey`) VALUES (?, ?));
        $stmt-&gt;bind_param('ss', $_REQUEST["value"], $_REQUEST["mykey"]);
        if(!$stmt-&gt;execute()) error($mysqli-&gt;error);
        $reply["id"] = $mysqli-&gt;insert_id;
        output();

    default: error('Invalid action.');
}

function error($msg){
    $GLOBALS['log'][] = $msg;
    $GLOBALS['reply']['status'] = 'error';
    $GLOBALS['reply']['error'] = $msg;
    output();
}

function output(){
    if($GLOBALS['logging']){
        file_put_contents('log/read_write_exercise.log',  implode(PHP_EOL, $GLOBALS['log']), FILE_APPEND) ;
    }
    header('Content-Type: application/json');
    echo json_encode($GLOBALS['reply'], JSON_PRETTY_PRINT);
    exit;
}