Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

<?php
        // db settings
        $dbserver = 'localhost';
        $dbuser = 'root';
        $dbpassword = 'root';
        
        error_reporting(E_ALL);
        
        /*
                Simple protocol:
                        - Inputs via POST variables. 
                        - Output is a string that can be evaluated into a JSON
                          First element of the array contains return status.
                                
                This simplified tutorial code should not be deployed without a security review.
        */
        
        @include "json.php";
        
        // set up response encoding 
        header("Content-Type: text/html; charset=utf-8");

        // util
        function getPostString($inName) {
                // make sure input strings are 'clean'
                return mysql_real_escape_string(@$_POST[$inName]);
        }
                
        // used for json encoding
        $json = new Services_JSON();
        
        function echoJson($inData) {
                global $json;
                // delay in ms
                $delay = getPostString('delay');
                if (!empty($delay))
                        usleep($delay * 1000);
                echo '/* ' . $json->encode($inData) . ' */';
        }
        
        function error($inMessage) {
                $inMessage = str_replace('"', '\\"', $inMessage);
                error_log($inMessage);
                //echo '/* ({error: true, message: "' . $inMessage . '"}) */';
                echoJson(array('error' => true, 'message' => $inMessage));
                exit;
        }


        function getArray($inResult, $inArray="true") {
                $o = Array();
                while ($row = ($inArray ? mysql_fetch_row($inResult) : mysql_fetch_object($inResult)))
                        $o[] = $row;
                return $o;      
        }
        
        // connect to DB
        mysql_connect($dbserver, $dbuser, $dbpassword);

        // select DB
        $database = getPostString("database");
        $database = ($database ? $database : $db);
        if (!mysql_select_db($database))
                error('failed to select db: ' . mysql_error());

        // select table
        $table = getPostString("table");
        $table = ($table ? $table : $dbtable);

        // cache
        $colCache = NULL;
        $pkCache = NULL;

        // set UTF8 output (MySql > 4.0)
        mysql_query("SET NAMES UTF8");
        
        // server, database, table meta data
        function getDatabases() {
                $result = mysql_query("SHOW DATABASES");
                $output = Array();
                while ($row = mysql_fetch_row($result)) {
                        $r = strtolower($row[0]);
                        if ($r != 'mysql' && $r != 'information_schema')
                                $output[] = $row[0];
                }       
                return $output; 
        }
        
        function getTables() {
                global $database;
                $result = mysql_query("SHOW TABLES FROM $database");
                $output = Array();
                while ($row = mysql_fetch_row($result))
                        $output[] = $row[0];
                return $output; 
        }
        
        function getColumns() {
                global $table, $colCache;
                if (!$colCache) {
                        $result = mysql_query("SHOW COLUMNS FROM `$table`");
                        return getArray($result, false);
                        $colCache = getArray($result, false);
                }
                return $colCache;       
        }
        
        // returns object: $this->name, $this->index
        function getPk() {
                global $pkCache;
                if (!$pkCache) {
                        $k = '';
                        $columns = getColumns();
                        for ($i=0; $i < count($columns); $i++) {
                                $c = $columns[$i];
                                if ($c->Key == 'PRI') {
                                        $k = $c->Field;
                                        break;
                                }       
                        }
                        $pkCache->index = $i;
                        $pkCache->name = $k;
                }       
                return $pkCache;
        }
        
        function getTableInfo() {
                global $table, $database;
                $c = getColumns();
                $r = rowcount();
                return array("count" => $r, "columns" => $c, "database" => $database, "table" => $table);
        }
        
        function getOldPostPkValue() {
                $pk = getPk();
                return getPostString('_o' . $pk->index);
        }
        
        function getNewPostPkValue() {
                $pk = getPk();
                return getPostString('_' . $pk->index);
        }
        
        function getPostColumns() {
                $columns = getColumns();
                for ($i=0, $a=array(), $p; (($p=getPostString("_".$i)) != ''); $i++) {
                        $r = new stdClass();
                        $r->name = $columns[$i]->Field;
                        $r->value = $p;
                        $a[] = $r;
                }       
                return $a;
        }
        
        function getOrderBy() {
                $ob = getPostString("orderby");
                if (is_numeric($ob)) {
                        $columns = getColumns();
                        $ob = $columns[intval($ob)-1]->Field;
                }
                return $ob;
        }
        
        function getWhere() {
                $w = getPostString("where");
                return ($w ? " WHERE $w" : "");
        }
        
        // basic operations
        function rowcount()     {
                global $table;
                $query = "SELECT COUNT(*) FROM `$table`" . getWhere();
                $result = mysql_query($query);
                if (!$result)
                        error("failed to perform query: $query. " . mysql_error());
                if ($row = mysql_fetch_row($result))
                        return $row[0];
                else
                        return 0;
        }
        
        function select($inQuery = '') {
                global $table;
                // built limit clause
                $lim = (int)getPostString("limit");
                $off = (int)getPostString("offset");
                $limit = ($lim || $off ? " LIMIT $off, $lim" : "");
                // build order by clause
                $desc = (boolean)getPostString("desc");
                $ob = getOrderBy();
                $orderby = ($ob ? " ORDER BY `" . $ob . "`" . ($desc ? " DESC" : "") : "");
                // build query
                $query = ($inQuery ? $inQuery : "SELECT * FROM `$table`" . getWhere() . $orderby . $limit);
                // execute query
                if (!$result = mysql_query($query))
                        error("failed to perform query: $query. " . mysql_error());
                // fetch each result row 
                return getArray($result);
        }

        function reflectRow() {
                global $table;
                $pk = getPk();
                $key = getNewPostPkValue();                     
                $where = "`$pk->name`=\"$key\"";
                return select("SELECT * FROM `$table` WHERE $where LIMIT 1");
        }
        
        function update() {
                // build set clause
                for ($i=0, $set = array(), $cols = getPostColumns(), $v; ($v=$cols[$i]); $i++)
                        $set[] = "`$v->name` = '$v->value'";
                $set = implode(', ', $set);
                // our table
                global $table;
                // build query
                $pk = getPk();
                $pkValue = getOldPostPkValue();
                $query = "UPDATE `$table` SET $set WHERE `$pk->name` = '$pkValue' LIMIT 1";
                // execute query
                if (!mysql_query($query))
                        error("failed to perform query: [$query]. " .
                                        "MySql says: [" . mysql_error() ."]");
                else {
                        return reflectRow();
                }       
        }
        
        function insert() {
                global $table;
                // build values clause
                for ($i=0, $values = array(), $cols = getPostColumns(), $v; ($v=$cols[$i]); $i++)
                        $values[] = $v->value;
                $values = '"' . implode('", "', $values) . '"';                 
                // build query
                $query = "INSERT INTO `$table` VALUES($values)";
                // execute query
                if (!mysql_query($query))
                        error("failed to perform query: [$query]. " .
                                        "MySql says: [" . mysql_error() ."]");
                else {
                        return reflectRow();
                }
        }
        
        function delete() {
                global $table;
                // build query
                $n = getPostString("count");
                $pk = getPk();
                for ($i = 0, $deleted=array(); $i < $n; $i++) {
                        $key = getPostString("_$i");
                        array_push($deleted, $key);
                        $query = "DELETE FROM `$table` WHERE `$pk->name`=\"$key\" LIMIT 1";
                        // execute query
                        if (!mysql_query($query) || mysql_affected_rows() != 1)
                                error("failed to perform query: [$query]. " .
                                        "Affected rows: " . mysql_affected_rows() .". " . 
                                        "MySql says: [" . mysql_error() ."]");
                }       
                return $deleted;                        
        }
        
        // find (full text search)
        function findData($inFindCol, $inFind, $inOrderBy, $inFullText) {
                global $table;
                $where = ($inFullText ? "WHERE MATCH(`$inFindCol`) AGAINST ('$inFind')" : "WHERE $inFindCol LIKE '$inFind'");
                $query = "SELECT * FROM $table $where $inOrderBy";
                $result = mysql_query($query);
                // return rows
                return getArray($result);
        }
        
        // binary search through sorted data, supports start point ($inFindFrom) and direction ($inFindForward)
        function findRow($inData, $inFindFrom=-1, $inFindForward) {
                $b = -1;
                $l = count($inData);
                if (!$inData)
                        return $b;
                if (!$inFindFrom==-1 || $l < 2)
                        $b = 0;
                else {
                        // binary search
                        $t = $l-1;
                        $b = 0;
                        while ($b <= $t) {
                                $p = floor(($b+$t)/2);
                                $d = $inData[$p][0];
                                if ($d < $inFindFrom)
                                        $b = $p + 1;
                                else if ($d > $inFindFrom)
                                        $t = $p - 1;
                                else {
                                        $b = $p;
                                        break;
                                }       
                        }       
                        if ($inFindFrom == $inData[$b][0]) {
                                // add or subtract 1
                                $b = ($inFindForward ? ($b+1 > $l-1 ? 0 : $b+1) : ($b-1 < 0 ? $l-1 : $b-1) );
                        }       
                        else if (!$inFindForward)
                                // subtract 1
                                $b = ($b-1 < 0 ? $l-1 : $b-1);
                }       
                return $inData[$b][0];
        }
        
        function buildFindWhere($inFindData, $inKey, $inCol) {
                $o = Array();
                foreach($inFindData as $row)
                        $o[] = $inCol . "='" . $row[$inKey] . "'";
                return (count($o) ? ' WHERE ' . implode(' OR ', $o) : '');
        }
                
        function find($inFindCol, $inFind='', $inOb='', $inFindFrom=0, $inFindForward=true, $inFullText=true) {
                global $table;
                // build order by clause
                $desc = (boolean)getPostString("desc");
                if (!$inOb)
                        $inOb = getOrderBy();
                if ($inOb)
                        $inOb = "`" . $inOb . "`"       ;
                $orderby = ($inOb ? " ORDER BY $inOb " . ($desc ? " DESC" : "") : "");
                // update inputs from post
                if (!$inFind)
                        $inFind = getPostString('findText');
                if (!$inFindCol)
                        $inFindCol = getPostString('findCol');  
                if (empty($inFindFrom))
                        $inFindFrom = getPostString('findFrom');
                $ff = getPostString('findForward');
                if ($ff)
                        $inFindForward = (strtolower($ff) == 'true' ? true : false);
                $ft = getPostString('findFullText');
                if ($ft)
                        $inFullText = (strtolower($ft) == 'true' ? true : false);       
                
                // get find data
                $f = findData($inFindCol, $inFind, $orderby,  $inFullText);
                $pk = getPk();

                // execute query
                $where = buildFindWhere($f, $pk->index, 'f');
                $query = "SELECT Row, f FROM (SELECT @row := @row + 1 AS Row, $pk->name as f FROM `$table` $orderby) AS tempTable $where";
                mysql_query('SET @row = -1;');
                if (!$result = mysql_query($query))
                        error("failed to perform query: $query. " . mysql_error());
                
                // return row number 
                return findRow(getArray($result), $inFindFrom, $inFindForward);
        }
        
        // our command list
        $cmds = array( 
                "count" => "rowcount", 
                "select" => "select",
                "update" => "update",
                "insert" => "insert",
                "delete" => "delete",
                "find" => "find",
                "databases" => "getDatabases",
                "tables" => "getTables",
                "columns" => "getColumns",
                "info" => "getTableInfo"
        );
                
        // process input params
        $cmd = @$_POST["command"];
        
        //$cmd="select";
        
        // dispatch command
        $func = @$cmds[$cmd];
        if (function_exists($func)) 
                echoJson(call_user_func($func));
        else
                error("bad command");
?>