PHP lightweight storage HTTP API
Clash 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());
//============================================================================
?>
beginner php file-system
add a comment |Â
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());
//============================================================================
?>
beginner php file-system
FWIW, this code fails badly on Windows when filenames have accents.
â rotoglup
Feb 1 at 14:47
add a comment |Â
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());
//============================================================================
?>
beginner php file-system
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());
//============================================================================
?>
beginner php file-system
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
add a comment |Â
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
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
There are a lot of points to review here :
- Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)
- Use files, to put things apart and avoid headaches
- Use classes, to make code clearer and reusable
- Do not expose everything at the root of your access point
- Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)
- Name your classes, functions and variables with explicit and clean and readable names.
- Reuse code
- 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()];
Thanks for your feedback, I'd rather not introduce aclass
for pure functions, I see that PHP supportsnamespace
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 implementationnew 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. Anywayclasses
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 haverenderer
,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
add a comment |Â
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 :
- Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)
- Use files, to put things apart and avoid headaches
- Use classes, to make code clearer and reusable
- Do not expose everything at the root of your access point
- Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)
- Name your classes, functions and variables with explicit and clean and readable names.
- Reuse code
- 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()];
Thanks for your feedback, I'd rather not introduce aclass
for pure functions, I see that PHP supportsnamespace
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 implementationnew 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. Anywayclasses
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 haverenderer
,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
add a comment |Â
up vote
2
down vote
accepted
There are a lot of points to review here :
- Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)
- Use files, to put things apart and avoid headaches
- Use classes, to make code clearer and reusable
- Do not expose everything at the root of your access point
- Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)
- Name your classes, functions and variables with explicit and clean and readable names.
- Reuse code
- 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()];
Thanks for your feedback, I'd rather not introduce aclass
for pure functions, I see that PHP supportsnamespace
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 implementationnew 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. Anywayclasses
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 haverenderer
,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
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
There are a lot of points to review here :
- Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)
- Use files, to put things apart and avoid headaches
- Use classes, to make code clearer and reusable
- Do not expose everything at the root of your access point
- Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)
- Name your classes, functions and variables with explicit and clean and readable names.
- Reuse code
- 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()];
There are a lot of points to review here :
- Choose a coding style, and stick to it (strings with ' or ", spaces, braces, casing...)
- Use files, to put things apart and avoid headaches
- Use classes, to make code clearer and reusable
- Do not expose everything at the root of your access point
- Do not rely on comments to make it work (i.e. "'/' at the end" can be enforced by code)
- Name your classes, functions and variables with explicit and clean and readable names.
- Reuse code
- 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()];
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 aclass
for pure functions, I see that PHP supportsnamespace
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 implementationnew 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. Anywayclasses
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 haverenderer
,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
add a comment |Â
Thanks for your feedback, I'd rather not introduce aclass
for pure functions, I see that PHP supportsnamespace
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 implementationnew 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. Anywayclasses
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 haverenderer
,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
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
FWIW, this code fails badly on Windows when filenames have accents.
â rotoglup
Feb 1 at 14:47