我正在学习PHP和'web‘开发(有离线编程背景)。
我计划设置一个简单的存储服务器API,我将使用javascript应用程序进行添加。
以下代码:
我从吊箱架获得了一些关于错误值和action
名称的灵感。
* ?action=permanently_delete&path=
* ?action=upload&path=
The provided 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 || !$dst) {
throw new _filesystem_HTTPException("Could not create file", 500);
}
// copy streams
while ($data = fread($src, 1024))
{
if ($data === FALSE) {
throw new _filesystem_HTTPException("Could not read source data", 500); // FIXME(nico) endpoint error ?
}
$written = fwrite($dst, $data, 1024);
if ($written != strlen($written)) {
throw new _filesystem_HTTPException("Could not write to file", 500);
}
}
}
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());
}
}
//============================================================================
?>
发布于 2018-01-24 23:58:07
这里有很多要点需要回顾:
总的来说,我不认为做您想做的事情是一个好主意,您可能正在您的服务器上实现安全漏洞。您应该考虑使用数据库进行存储,或者快速了解安全性。
尽管如此,下面的代码可能并不完全工作(因为我没有测试它),但是应该给您一个很好的洞察力。从现在开始,一个很好的实践就是编写代码并运行一些单元测试。
* ?action=permanently_delete&path=
* ?action=upload&path=
The provided 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
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 || !$dst) {
throw new StorageAPIException('Could not create file', 500);
}
// copy streams
while ($data = fread($src, 1024))
{
if ($data === false) {
throw new StorageAPIException('Could not read source data', 500); // FIXME(nico) endpoint error ?
}
$written = fwrite($dst, $data, 1024);
if ($written != strlen($written)) {
throw new StorageAPIException('Could not write to file', 500);
}
}
}
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
}
}
['.tag'=>'other'], 'http_status_code'=>$this->getCode(), 'http_status_message'=>$this->getMessage()];
}
}
https://codereview.stackexchange.com/questions/185908
复制相似问题