PHP lightweight storage HTTP API

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I'm learning PHP and 'web' development (having an offline programming background).



I plan to setup a simple storage server API that I'll adress with a javascript application.



The following code :



  • does not consider authentification

  • does provide file upload/deletion, folder listing

I got some inspiration from the Dropbox REST API for error values and action names.



<?php
/*
the 'API' provided is :

* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);

define('ROOT_FOLDER', 'files/' ); // IMPORTANT(nico) '/' at the end

//============================================================================

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');

$result = null;

try

$action = _filesystem_checked_GET('action');

switch ($action)

case 'list_folder':
$path = _filesystem_checked_GET('path');
$result = _filesystem_list_folder($path);
break;

case 'permanently_delete':
$path = _filesystem_checked_GET('path');
$result = _filesystem_permanently_delete($path);
break;

case 'upload':
$path = _filesystem_checked_GET('path');
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new _filesystem_HTTPException('Bad Request', 400, 'POST expected');

$result = _filesystem_upload($path);
break;

default:
throw new _filesystem_HTTPException('Bad Request', 400, 'Unknown action');


catch (_filesystem_HTTPException $e)
$e->setErrorHeader();
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->content];

catch (Exception $e)
header("HTTP/1.1 500 Internal error");
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->getMessage()];


header('Content-type:application/json;charset=utf-8');
echo json_encode($result);

//============================================================================

function _filesystem_upload($path)

$abspath = _filesystem_abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new _filesystem_HTTPException("`tempnam` failed", 500);


try

$dst = fopen($temppath, "wb");
$src = fopen("php://input", "r"); // POST raw data

try

if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new _filesystem_HTTPException("Could not finalize file", 500);



finally

if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = _filesystem_metadata($name, $abspath);
return $result;


//----------------------------------------------------------------------------

function _filesystem_permanently_delete($path)

$abspath = _filesystem_abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting

return null;

else

return ['error'=> ['.tag'=> 'other'], 'error_summary'=> "Could not unlink file"];



//----------------------------------------------------------------------------

function _filesystem_list_folder($path)

$abspath = _filesystem_abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = _filesystem_path_join($abspath, $name);

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

$metadata = _filesystem_metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return [ 'entries'=> $result, 'has_more'=> false ];


//============================================================================

function _filesystem_metadata($name, $path)

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

return [ ".tag"=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size ];


function _filesystem_abspath($path)

return ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'


function _filesystem_path_join($root, $path)

return $root . $path; // FIXME(nico) check '/' & stuff


function _filesystem_checked_GET($varname)
if (!isset($_GET[$varname]))
throw new _filesystem_HTTPException('Bad Request', 400, 'Missing parameter `' . $varname . '`');

return $_GET[$varname];


class _filesystem_HTTPException extends Exception
public $content = null;
public function __construct($message = null, $code = 501, $content = null)
parent::__construct($message, $code);
$this->content = $content;

public function setErrorHeader()
header("HTTP/1.1 " . $this->code . ' ' . $this->getMessage());



//============================================================================

?>






share|improve this question





















  • FWIW, this code fails badly on Windows when filenames have accents.
    – rotoglup
    Feb 1 at 14:47
















up vote
2
down vote

favorite












I'm learning PHP and 'web' development (having an offline programming background).



I plan to setup a simple storage server API that I'll adress with a javascript application.



The following code :



  • does not consider authentification

  • does provide file upload/deletion, folder listing

I got some inspiration from the Dropbox REST API for error values and action names.



<?php
/*
the 'API' provided is :

* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);

define('ROOT_FOLDER', 'files/' ); // IMPORTANT(nico) '/' at the end

//============================================================================

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');

$result = null;

try

$action = _filesystem_checked_GET('action');

switch ($action)

case 'list_folder':
$path = _filesystem_checked_GET('path');
$result = _filesystem_list_folder($path);
break;

case 'permanently_delete':
$path = _filesystem_checked_GET('path');
$result = _filesystem_permanently_delete($path);
break;

case 'upload':
$path = _filesystem_checked_GET('path');
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new _filesystem_HTTPException('Bad Request', 400, 'POST expected');

$result = _filesystem_upload($path);
break;

default:
throw new _filesystem_HTTPException('Bad Request', 400, 'Unknown action');


catch (_filesystem_HTTPException $e)
$e->setErrorHeader();
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->content];

catch (Exception $e)
header("HTTP/1.1 500 Internal error");
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->getMessage()];


header('Content-type:application/json;charset=utf-8');
echo json_encode($result);

//============================================================================

function _filesystem_upload($path)

$abspath = _filesystem_abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new _filesystem_HTTPException("`tempnam` failed", 500);


try

$dst = fopen($temppath, "wb");
$src = fopen("php://input", "r"); // POST raw data

try

if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new _filesystem_HTTPException("Could not finalize file", 500);



finally

if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = _filesystem_metadata($name, $abspath);
return $result;


//----------------------------------------------------------------------------

function _filesystem_permanently_delete($path)

$abspath = _filesystem_abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting

return null;

else

return ['error'=> ['.tag'=> 'other'], 'error_summary'=> "Could not unlink file"];



//----------------------------------------------------------------------------

function _filesystem_list_folder($path)

$abspath = _filesystem_abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = _filesystem_path_join($abspath, $name);

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

$metadata = _filesystem_metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return [ 'entries'=> $result, 'has_more'=> false ];


//============================================================================

function _filesystem_metadata($name, $path)

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

return [ ".tag"=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size ];


function _filesystem_abspath($path)

return ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'


function _filesystem_path_join($root, $path)

return $root . $path; // FIXME(nico) check '/' & stuff


function _filesystem_checked_GET($varname)
if (!isset($_GET[$varname]))
throw new _filesystem_HTTPException('Bad Request', 400, 'Missing parameter `' . $varname . '`');

return $_GET[$varname];


class _filesystem_HTTPException extends Exception
public $content = null;
public function __construct($message = null, $code = 501, $content = null)
parent::__construct($message, $code);
$this->content = $content;

public function setErrorHeader()
header("HTTP/1.1 " . $this->code . ' ' . $this->getMessage());



//============================================================================

?>






share|improve this question





















  • FWIW, this code fails badly on Windows when filenames have accents.
    – rotoglup
    Feb 1 at 14:47












up vote
2
down vote

favorite









up vote
2
down vote

favorite











I'm learning PHP and 'web' development (having an offline programming background).



I plan to setup a simple storage server API that I'll adress with a javascript application.



The following code :



  • does not consider authentification

  • does provide file upload/deletion, folder listing

I got some inspiration from the Dropbox REST API for error values and action names.



<?php
/*
the 'API' provided is :

* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);

define('ROOT_FOLDER', 'files/' ); // IMPORTANT(nico) '/' at the end

//============================================================================

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');

$result = null;

try

$action = _filesystem_checked_GET('action');

switch ($action)

case 'list_folder':
$path = _filesystem_checked_GET('path');
$result = _filesystem_list_folder($path);
break;

case 'permanently_delete':
$path = _filesystem_checked_GET('path');
$result = _filesystem_permanently_delete($path);
break;

case 'upload':
$path = _filesystem_checked_GET('path');
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new _filesystem_HTTPException('Bad Request', 400, 'POST expected');

$result = _filesystem_upload($path);
break;

default:
throw new _filesystem_HTTPException('Bad Request', 400, 'Unknown action');


catch (_filesystem_HTTPException $e)
$e->setErrorHeader();
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->content];

catch (Exception $e)
header("HTTP/1.1 500 Internal error");
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->getMessage()];


header('Content-type:application/json;charset=utf-8');
echo json_encode($result);

//============================================================================

function _filesystem_upload($path)

$abspath = _filesystem_abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new _filesystem_HTTPException("`tempnam` failed", 500);


try

$dst = fopen($temppath, "wb");
$src = fopen("php://input", "r"); // POST raw data

try

if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new _filesystem_HTTPException("Could not finalize file", 500);



finally

if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = _filesystem_metadata($name, $abspath);
return $result;


//----------------------------------------------------------------------------

function _filesystem_permanently_delete($path)

$abspath = _filesystem_abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting

return null;

else

return ['error'=> ['.tag'=> 'other'], 'error_summary'=> "Could not unlink file"];



//----------------------------------------------------------------------------

function _filesystem_list_folder($path)

$abspath = _filesystem_abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = _filesystem_path_join($abspath, $name);

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

$metadata = _filesystem_metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return [ 'entries'=> $result, 'has_more'=> false ];


//============================================================================

function _filesystem_metadata($name, $path)

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

return [ ".tag"=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size ];


function _filesystem_abspath($path)

return ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'


function _filesystem_path_join($root, $path)

return $root . $path; // FIXME(nico) check '/' & stuff


function _filesystem_checked_GET($varname)
if (!isset($_GET[$varname]))
throw new _filesystem_HTTPException('Bad Request', 400, 'Missing parameter `' . $varname . '`');

return $_GET[$varname];


class _filesystem_HTTPException extends Exception
public $content = null;
public function __construct($message = null, $code = 501, $content = null)
parent::__construct($message, $code);
$this->content = $content;

public function setErrorHeader()
header("HTTP/1.1 " . $this->code . ' ' . $this->getMessage());



//============================================================================

?>






share|improve this question













I'm learning PHP and 'web' development (having an offline programming background).



I plan to setup a simple storage server API that I'll adress with a javascript application.



The following code :



  • does not consider authentification

  • does provide file upload/deletion, folder listing

I got some inspiration from the Dropbox REST API for error values and action names.



<?php
/*
the 'API' provided is :

* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);

define('ROOT_FOLDER', 'files/' ); // IMPORTANT(nico) '/' at the end

//============================================================================

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');

$result = null;

try

$action = _filesystem_checked_GET('action');

switch ($action)

case 'list_folder':
$path = _filesystem_checked_GET('path');
$result = _filesystem_list_folder($path);
break;

case 'permanently_delete':
$path = _filesystem_checked_GET('path');
$result = _filesystem_permanently_delete($path);
break;

case 'upload':
$path = _filesystem_checked_GET('path');
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new _filesystem_HTTPException('Bad Request', 400, 'POST expected');

$result = _filesystem_upload($path);
break;

default:
throw new _filesystem_HTTPException('Bad Request', 400, 'Unknown action');


catch (_filesystem_HTTPException $e)
$e->setErrorHeader();
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->content];

catch (Exception $e)
header("HTTP/1.1 500 Internal error");
$result = ['error'=> ['.tag'=> 'other'], 'error_summary'=> $e->getMessage()];


header('Content-type:application/json;charset=utf-8');
echo json_encode($result);

//============================================================================

function _filesystem_upload($path)

$abspath = _filesystem_abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new _filesystem_HTTPException("`tempnam` failed", 500);


try

$dst = fopen($temppath, "wb");
$src = fopen("php://input", "r"); // POST raw data

try

if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new _filesystem_HTTPException("Could not finalize file", 500);



finally

if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = _filesystem_metadata($name, $abspath);
return $result;


//----------------------------------------------------------------------------

function _filesystem_permanently_delete($path)

$abspath = _filesystem_abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting

return null;

else

return ['error'=> ['.tag'=> 'other'], 'error_summary'=> "Could not unlink file"];



//----------------------------------------------------------------------------

function _filesystem_list_folder($path)

$abspath = _filesystem_abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = _filesystem_path_join($abspath, $name);

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

$metadata = _filesystem_metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return [ 'entries'=> $result, 'has_more'=> false ];


//============================================================================

function _filesystem_metadata($name, $path)

$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path)) $tag='folder';
elseif (is_file($path)) $tag='file';

return [ ".tag"=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size ];


function _filesystem_abspath($path)

return ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'


function _filesystem_path_join($root, $path)

return $root . $path; // FIXME(nico) check '/' & stuff


function _filesystem_checked_GET($varname)
if (!isset($_GET[$varname]))
throw new _filesystem_HTTPException('Bad Request', 400, 'Missing parameter `' . $varname . '`');

return $_GET[$varname];


class _filesystem_HTTPException extends Exception
public $content = null;
public function __construct($message = null, $code = 501, $content = null)
parent::__construct($message, $code);
$this->content = $content;

public function setErrorHeader()
header("HTTP/1.1 " . $this->code . ' ' . $this->getMessage());



//============================================================================

?>








share|improve this question












share|improve this question




share|improve this question








edited Jan 24 at 23:43









200_success

123k14143401




123k14143401









asked Jan 24 at 21:59









rotoglup

1235




1235











  • FWIW, this code fails badly on Windows when filenames have accents.
    – rotoglup
    Feb 1 at 14:47
















  • FWIW, this code fails badly on Windows when filenames have accents.
    – rotoglup
    Feb 1 at 14:47















FWIW, this code fails badly on Windows when filenames have accents.
– rotoglup
Feb 1 at 14:47




FWIW, this code fails badly on Windows when filenames have accents.
– rotoglup
Feb 1 at 14:47










1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










There are a lot of points to review here :



  1. Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)

  2. Use files, to put things apart and avoid headaches

  3. Use classes, to make code clearer and reusable

  4. Do not expose everything at the root of your access point

  5. Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)

  6. Name your classes, functions and variables with explicit and clean and readable names.

  7. Reuse code

  8. Shorten your code with early returns (guards) and short functions

As a whole review, I do not believe doing what you want to do to be a good idea, you may be implementing a security breach on your server. You should consider using a database for storage or learn real fast about security.



That being said, the code below may not fully work (because I didn't test it) but should give you a good insight. A good practice from now on would be to code and run some unit tests.



web/index.php



<?php
/*
the 'API' provided is :
* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' class constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);
require_once('../lib/StorageAPI/Controler.php');
require_once('../lib/StorageAPI/Exception.php');
StorageAPIControler::run('files/'); // IMPORTANT(nico) '/' at the end


lib/StorageAPI/Controler.php



<?php
class StorageAPIControler
public static $root_folder;

public static function run($root_folder)
self::$root_folder = $root_folder;

try
$action = self::readGET('action');
$method = 'api_'.$action;
if(!method_exists(__CLASS__,$method))
$method = 'api_default';
$result = self::$method();

catch (StorageAPIException $storage_api_exception)
$result = $storage_api_exception->getResult();

catch (Exception $exception)
$storage_api_exception = new StorageAPIException('Internal Server Error - '.$exception->getMessage(), 500);
$result = $storage_api_exception->getResult();


self::output($result);

public static function output($result)
if(!isset($result['http_status_code']))
$result['http_status_code'] = 200;
if(!isset($result['http_status_message']))
$result['http_status_message'] = 'OK';

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type:application/json; charset=utf-8');
echo json_encode($result);


public static function api_list_folder()
$path = self::readGET('path');
$entries = self::list_folder($path);
return [ 'entries'=> $result, 'has_more'=> false ];

public static function list_folder($path)
$abspath = self::abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = self::path_join($abspath, $name);

$metadata = self::metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return $entries;


public static function api_permanently_delete()
$path = self::readGET('path');
$status = self::permanently_delete($path);
return ; // TODO

public static function permanently_delete($path)
$abspath = self::abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting
return true;

throw new StorageAPIException('Could not unlink file');


public static function api_upload()
$path = self::readGET('path');
$result = self::upload($path);

public static function upload($path)
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new StorageAPIException('Bad Request - POST expected', 400);


$abspath = self::abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new StorageAPIException('"tempnam" failed', 500);


try
$dst = fopen($temppath, 'wb');
$src = fopen('php://input', 'r'); // POST raw data

try
if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new StorageAPIException('Could not finalize file', 500);


finally
if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = self::metadata($name, $abspath);
return $result;


public static function api_default()
throw new StorageAPIException('Bad Request - Unknown action', 400);


public static function readGET($varname)
if (!isset($_GET[$varname]))
throw new StorageAPIException('Bad Request - Missing parameter "'.$varname.'"', 400);

return $_GET[$varname];

public static function metadata($name, $path)
$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path))
$tag = 'folder';

elseif (is_file($path))
$tag = 'file';

return [ '.tag'=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size];

public static function abspath($path)
return self::$ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'

public static function path_join($root, $path)
return $root . $path; // FIXME(nico) check '/' & stuff




lib/StorageAPI/Exception.php



<?php
class StorageAPIException extends Exception
public function __construct($message = null, $code = 501)
parent::__construct($message, $code);

public function getResult()
return ['error'=>['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];







share|improve this answer























  • Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
    – rotoglup
    Jan 25 at 12:19










  • namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
    – Geompse
    Jan 25 at 15:50











  • Most projects starts as one simple script file and ends as a large application.
    – Geompse
    Jan 25 at 15:51










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185908%2fphp-lightweight-storage-http-api%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted










There are a lot of points to review here :



  1. Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)

  2. Use files, to put things apart and avoid headaches

  3. Use classes, to make code clearer and reusable

  4. Do not expose everything at the root of your access point

  5. Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)

  6. Name your classes, functions and variables with explicit and clean and readable names.

  7. Reuse code

  8. Shorten your code with early returns (guards) and short functions

As a whole review, I do not believe doing what you want to do to be a good idea, you may be implementing a security breach on your server. You should consider using a database for storage or learn real fast about security.



That being said, the code below may not fully work (because I didn't test it) but should give you a good insight. A good practice from now on would be to code and run some unit tests.



web/index.php



<?php
/*
the 'API' provided is :
* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' class constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);
require_once('../lib/StorageAPI/Controler.php');
require_once('../lib/StorageAPI/Exception.php');
StorageAPIControler::run('files/'); // IMPORTANT(nico) '/' at the end


lib/StorageAPI/Controler.php



<?php
class StorageAPIControler
public static $root_folder;

public static function run($root_folder)
self::$root_folder = $root_folder;

try
$action = self::readGET('action');
$method = 'api_'.$action;
if(!method_exists(__CLASS__,$method))
$method = 'api_default';
$result = self::$method();

catch (StorageAPIException $storage_api_exception)
$result = $storage_api_exception->getResult();

catch (Exception $exception)
$storage_api_exception = new StorageAPIException('Internal Server Error - '.$exception->getMessage(), 500);
$result = $storage_api_exception->getResult();


self::output($result);

public static function output($result)
if(!isset($result['http_status_code']))
$result['http_status_code'] = 200;
if(!isset($result['http_status_message']))
$result['http_status_message'] = 'OK';

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type:application/json; charset=utf-8');
echo json_encode($result);


public static function api_list_folder()
$path = self::readGET('path');
$entries = self::list_folder($path);
return [ 'entries'=> $result, 'has_more'=> false ];

public static function list_folder($path)
$abspath = self::abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = self::path_join($abspath, $name);

$metadata = self::metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return $entries;


public static function api_permanently_delete()
$path = self::readGET('path');
$status = self::permanently_delete($path);
return ; // TODO

public static function permanently_delete($path)
$abspath = self::abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting
return true;

throw new StorageAPIException('Could not unlink file');


public static function api_upload()
$path = self::readGET('path');
$result = self::upload($path);

public static function upload($path)
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new StorageAPIException('Bad Request - POST expected', 400);


$abspath = self::abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new StorageAPIException('"tempnam" failed', 500);


try
$dst = fopen($temppath, 'wb');
$src = fopen('php://input', 'r'); // POST raw data

try
if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new StorageAPIException('Could not finalize file', 500);


finally
if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = self::metadata($name, $abspath);
return $result;


public static function api_default()
throw new StorageAPIException('Bad Request - Unknown action', 400);


public static function readGET($varname)
if (!isset($_GET[$varname]))
throw new StorageAPIException('Bad Request - Missing parameter "'.$varname.'"', 400);

return $_GET[$varname];

public static function metadata($name, $path)
$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path))
$tag = 'folder';

elseif (is_file($path))
$tag = 'file';

return [ '.tag'=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size];

public static function abspath($path)
return self::$ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'

public static function path_join($root, $path)
return $root . $path; // FIXME(nico) check '/' & stuff




lib/StorageAPI/Exception.php



<?php
class StorageAPIException extends Exception
public function __construct($message = null, $code = 501)
parent::__construct($message, $code);

public function getResult()
return ['error'=>['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];







share|improve this answer























  • Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
    – rotoglup
    Jan 25 at 12:19










  • namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
    – Geompse
    Jan 25 at 15:50











  • Most projects starts as one simple script file and ends as a large application.
    – Geompse
    Jan 25 at 15:51














up vote
2
down vote



accepted










There are a lot of points to review here :



  1. Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)

  2. Use files, to put things apart and avoid headaches

  3. Use classes, to make code clearer and reusable

  4. Do not expose everything at the root of your access point

  5. Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)

  6. Name your classes, functions and variables with explicit and clean and readable names.

  7. Reuse code

  8. Shorten your code with early returns (guards) and short functions

As a whole review, I do not believe doing what you want to do to be a good idea, you may be implementing a security breach on your server. You should consider using a database for storage or learn real fast about security.



That being said, the code below may not fully work (because I didn't test it) but should give you a good insight. A good practice from now on would be to code and run some unit tests.



web/index.php



<?php
/*
the 'API' provided is :
* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' class constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);
require_once('../lib/StorageAPI/Controler.php');
require_once('../lib/StorageAPI/Exception.php');
StorageAPIControler::run('files/'); // IMPORTANT(nico) '/' at the end


lib/StorageAPI/Controler.php



<?php
class StorageAPIControler
public static $root_folder;

public static function run($root_folder)
self::$root_folder = $root_folder;

try
$action = self::readGET('action');
$method = 'api_'.$action;
if(!method_exists(__CLASS__,$method))
$method = 'api_default';
$result = self::$method();

catch (StorageAPIException $storage_api_exception)
$result = $storage_api_exception->getResult();

catch (Exception $exception)
$storage_api_exception = new StorageAPIException('Internal Server Error - '.$exception->getMessage(), 500);
$result = $storage_api_exception->getResult();


self::output($result);

public static function output($result)
if(!isset($result['http_status_code']))
$result['http_status_code'] = 200;
if(!isset($result['http_status_message']))
$result['http_status_message'] = 'OK';

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type:application/json; charset=utf-8');
echo json_encode($result);


public static function api_list_folder()
$path = self::readGET('path');
$entries = self::list_folder($path);
return [ 'entries'=> $result, 'has_more'=> false ];

public static function list_folder($path)
$abspath = self::abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = self::path_join($abspath, $name);

$metadata = self::metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return $entries;


public static function api_permanently_delete()
$path = self::readGET('path');
$status = self::permanently_delete($path);
return ; // TODO

public static function permanently_delete($path)
$abspath = self::abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting
return true;

throw new StorageAPIException('Could not unlink file');


public static function api_upload()
$path = self::readGET('path');
$result = self::upload($path);

public static function upload($path)
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new StorageAPIException('Bad Request - POST expected', 400);


$abspath = self::abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new StorageAPIException('"tempnam" failed', 500);


try
$dst = fopen($temppath, 'wb');
$src = fopen('php://input', 'r'); // POST raw data

try
if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new StorageAPIException('Could not finalize file', 500);


finally
if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = self::metadata($name, $abspath);
return $result;


public static function api_default()
throw new StorageAPIException('Bad Request - Unknown action', 400);


public static function readGET($varname)
if (!isset($_GET[$varname]))
throw new StorageAPIException('Bad Request - Missing parameter "'.$varname.'"', 400);

return $_GET[$varname];

public static function metadata($name, $path)
$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path))
$tag = 'folder';

elseif (is_file($path))
$tag = 'file';

return [ '.tag'=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size];

public static function abspath($path)
return self::$ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'

public static function path_join($root, $path)
return $root . $path; // FIXME(nico) check '/' & stuff




lib/StorageAPI/Exception.php



<?php
class StorageAPIException extends Exception
public function __construct($message = null, $code = 501)
parent::__construct($message, $code);

public function getResult()
return ['error'=>['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];







share|improve this answer























  • Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
    – rotoglup
    Jan 25 at 12:19










  • namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
    – Geompse
    Jan 25 at 15:50











  • Most projects starts as one simple script file and ends as a large application.
    – Geompse
    Jan 25 at 15:51












up vote
2
down vote



accepted







up vote
2
down vote



accepted






There are a lot of points to review here :



  1. Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)

  2. Use files, to put things apart and avoid headaches

  3. Use classes, to make code clearer and reusable

  4. Do not expose everything at the root of your access point

  5. Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)

  6. Name your classes, functions and variables with explicit and clean and readable names.

  7. Reuse code

  8. Shorten your code with early returns (guards) and short functions

As a whole review, I do not believe doing what you want to do to be a good idea, you may be implementing a security breach on your server. You should consider using a database for storage or learn real fast about security.



That being said, the code below may not fully work (because I didn't test it) but should give you a good insight. A good practice from now on would be to code and run some unit tests.



web/index.php



<?php
/*
the 'API' provided is :
* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' class constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);
require_once('../lib/StorageAPI/Controler.php');
require_once('../lib/StorageAPI/Exception.php');
StorageAPIControler::run('files/'); // IMPORTANT(nico) '/' at the end


lib/StorageAPI/Controler.php



<?php
class StorageAPIControler
public static $root_folder;

public static function run($root_folder)
self::$root_folder = $root_folder;

try
$action = self::readGET('action');
$method = 'api_'.$action;
if(!method_exists(__CLASS__,$method))
$method = 'api_default';
$result = self::$method();

catch (StorageAPIException $storage_api_exception)
$result = $storage_api_exception->getResult();

catch (Exception $exception)
$storage_api_exception = new StorageAPIException('Internal Server Error - '.$exception->getMessage(), 500);
$result = $storage_api_exception->getResult();


self::output($result);

public static function output($result)
if(!isset($result['http_status_code']))
$result['http_status_code'] = 200;
if(!isset($result['http_status_message']))
$result['http_status_message'] = 'OK';

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type:application/json; charset=utf-8');
echo json_encode($result);


public static function api_list_folder()
$path = self::readGET('path');
$entries = self::list_folder($path);
return [ 'entries'=> $result, 'has_more'=> false ];

public static function list_folder($path)
$abspath = self::abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = self::path_join($abspath, $name);

$metadata = self::metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return $entries;


public static function api_permanently_delete()
$path = self::readGET('path');
$status = self::permanently_delete($path);
return ; // TODO

public static function permanently_delete($path)
$abspath = self::abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting
return true;

throw new StorageAPIException('Could not unlink file');


public static function api_upload()
$path = self::readGET('path');
$result = self::upload($path);

public static function upload($path)
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new StorageAPIException('Bad Request - POST expected', 400);


$abspath = self::abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new StorageAPIException('"tempnam" failed', 500);


try
$dst = fopen($temppath, 'wb');
$src = fopen('php://input', 'r'); // POST raw data

try
if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new StorageAPIException('Could not finalize file', 500);


finally
if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = self::metadata($name, $abspath);
return $result;


public static function api_default()
throw new StorageAPIException('Bad Request - Unknown action', 400);


public static function readGET($varname)
if (!isset($_GET[$varname]))
throw new StorageAPIException('Bad Request - Missing parameter "'.$varname.'"', 400);

return $_GET[$varname];

public static function metadata($name, $path)
$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path))
$tag = 'folder';

elseif (is_file($path))
$tag = 'file';

return [ '.tag'=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size];

public static function abspath($path)
return self::$ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'

public static function path_join($root, $path)
return $root . $path; // FIXME(nico) check '/' & stuff




lib/StorageAPI/Exception.php



<?php
class StorageAPIException extends Exception
public function __construct($message = null, $code = 501)
parent::__construct($message, $code);

public function getResult()
return ['error'=>['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];







share|improve this answer















There are a lot of points to review here :



  1. Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)

  2. Use files, to put things apart and avoid headaches

  3. Use classes, to make code clearer and reusable

  4. Do not expose everything at the root of your access point

  5. Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)

  6. Name your classes, functions and variables with explicit and clean and readable names.

  7. Reuse code

  8. Shorten your code with early returns (guards) and short functions

As a whole review, I do not believe doing what you want to do to be a good idea, you may be implementing a security breach on your server. You should consider using a database for storage or learn real fast about security.



That being said, the code below may not fully work (because I didn't test it) but should give you a good insight. A good practice from now on would be to code and run some unit tests.



web/index.php



<?php
/*
the 'API' provided is :
* ?action=list_folder&path=</some/path>
* ?action=permanently_delete&path=</some/path>
* ?action=upload&path=</some/path>

The provided </some/path> values are joined to 'ROOT_FOLDER' class constant.

Can't create folders or download files.

Needs PHP 5.5+ for `finally` clauses.
*/

error_reporting(0);
require_once('../lib/StorageAPI/Controler.php');
require_once('../lib/StorageAPI/Exception.php');
StorageAPIControler::run('files/'); // IMPORTANT(nico) '/' at the end


lib/StorageAPI/Controler.php



<?php
class StorageAPIControler
public static $root_folder;

public static function run($root_folder)
self::$root_folder = $root_folder;

try
$action = self::readGET('action');
$method = 'api_'.$action;
if(!method_exists(__CLASS__,$method))
$method = 'api_default';
$result = self::$method();

catch (StorageAPIException $storage_api_exception)
$result = $storage_api_exception->getResult();

catch (Exception $exception)
$storage_api_exception = new StorageAPIException('Internal Server Error - '.$exception->getMessage(), 500);
$result = $storage_api_exception->getResult();


self::output($result);

public static function output($result)
if(!isset($result['http_status_code']))
$result['http_status_code'] = 200;
if(!isset($result['http_status_message']))
$result['http_status_message'] = 'OK';

header('Access-Control-Allow-Origin: *');
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type:application/json; charset=utf-8');
echo json_encode($result);


public static function api_list_folder()
$path = self::readGET('path');
$entries = self::list_folder($path);
return [ 'entries'=> $result, 'has_more'=> false ];

public static function list_folder($path)
$abspath = self::abspath($path);
$names = array_diff(scandir($abspath), array('..', '.'));
$result = ;
foreach ($names as $name)
$path = self::path_join($abspath, $name);

$metadata = self::metadata($name, $path);
if ($metadata['.tag'] != null)
// NOTE(nico) do not include info on 'undefined' filesystem items
$result = $metadata;


return $entries;


public static function api_permanently_delete()
$path = self::readGET('path');
$status = self::permanently_delete($path);
return ; // TODO

public static function permanently_delete($path)
$abspath = self::abspath($path);
if (unlink($abspath)) // FIXME(nico) can trigger a warning, check file_exists first, and improve error reporting
return true;

throw new StorageAPIException('Could not unlink file');


public static function api_upload()
$path = self::readGET('path');
$result = self::upload($path);

public static function upload($path)
if ($_SERVER['REQUEST_METHOD'] !== 'POST')
throw new StorageAPIException('Bad Request - POST expected', 400);


$abspath = self::abspath($path);

$temppath = tempnam(dirname($abspath), 'temp');
if (!$temppath)
throw new StorageAPIException('"tempnam" failed', 500);


try
$dst = fopen($temppath, 'wb');
$src = fopen('php://input', 'r'); // POST raw data

try
if (!$src
finally
fclose($src);
fclose($dst);


// finalize destination file
if (!rename($temppath, $abspath))
throw new StorageAPIException('Could not finalize file', 500);


finally
if (file_exists($temppath))
unlink($temppath);



$name = basename($abspath);
$result = self::metadata($name, $abspath);
return $result;


public static function api_default()
throw new StorageAPIException('Bad Request - Unknown action', 400);


public static function readGET($varname)
if (!isset($_GET[$varname]))
throw new StorageAPIException('Bad Request - Missing parameter "'.$varname.'"', 400);

return $_GET[$varname];

public static function metadata($name, $path)
$size = filesize($path);
$server_modified = date(DATE_ISO8601, filemtime($path));
$tag = null;
if (is_dir($path))
$tag = 'folder';

elseif (is_file($path))
$tag = 'file';

return [ '.tag'=>$tag, 'name'=>$name, 'server_modified'=>$server_modified, 'size'=>$size];

public static function abspath($path)
return self::$ROOT_FOLDER . $path; // FIXME(nico) security check, path should be absolute starting with '/'

public static function path_join($root, $path)
return $root . $path; // FIXME(nico) check '/' & stuff




lib/StorageAPI/Exception.php



<?php
class StorageAPIException extends Exception
public function __construct($message = null, $code = 501)
parent::__construct($message, $code);

public function getResult()
return ['error'=>['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];








share|improve this answer















share|improve this answer



share|improve this answer








edited Jan 29 at 17:30









Sam Onela

5,88461545




5,88461545











answered Jan 24 at 23:58









Geompse

912




912











  • Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
    – rotoglup
    Jan 25 at 12:19










  • namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
    – Geompse
    Jan 25 at 15:50











  • Most projects starts as one simple script file and ends as a large application.
    – Geompse
    Jan 25 at 15:51
















  • Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
    – rotoglup
    Jan 25 at 12:19










  • namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
    – Geompse
    Jan 25 at 15:50











  • Most projects starts as one simple script file and ends as a large application.
    – Geompse
    Jan 25 at 15:51















Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
– rotoglup
Jan 25 at 12:19




Thanks for your feedback, I'd rather not introduce a class for pure functions, I see that PHP supports namespace to avoid name collisions, what do you think of it ? Maybe not used often ?
– rotoglup
Jan 25 at 12:19












namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
– Geompse
Jan 25 at 15:50





namespace is a valid pattern, but I don't like the PHP implementation new MyNamespaceMyClass(), so I don't use it. I believe that since in your case you don't use external librairies you don't need to use namespaces. Anyway classes are the way to go to have a clean code, that will be easily readable and maintenable. I kept it simple to not lose you too much towards your original code, but you can add more classes : controler, helper, filesystem, ... I.E if you want to give the choice of the output format (JSON/XML/...) you should have renderer, rendererJson, renderXml...
– Geompse
Jan 25 at 15:50













Most projects starts as one simple script file and ends as a large application.
– Geompse
Jan 25 at 15:51




Most projects starts as one simple script file and ends as a large application.
– Geompse
Jan 25 at 15:51












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185908%2fphp-lightweight-storage-http-api%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Chat program with C++ and SFML

Function to Return a JSON Like Objects Using VBA Collections and Arrays

Will my employers contract hold up in court?