net-tools/simple_framework

用于简单应用框架的Composer库

1.1.31 2023-10-27 19:11 UTC

README

用于创建简单Web应用的Composer库

此包定义了一个可用于创建简单Web应用的框架。最终用户可以专注于“业务”代码部分,而无需关注清理用户提交的数据、响应XMLHttpRequest等问题。

安装说明

要安装net-tools/simple_framework包,只需通过composer要求: require net-tools/simple_framework:^1.0.0

示例文件

在包中有一个名为samples的子目录,其中包含一个非常简单的应用。请首先阅读本README,然后您可以参考此示例文件。

如何使用?

框架预览

该框架专注于命令,即PHP代码“响应”发送到应用的请求。请求可以是GET/POST请求(可能包含文件上传)或XMLHttpRequest。命令“响应”请求,返回一个可选值

  • PHP值(任何数据类型): 当命令仅执行一些后台操作,如计算并返回计算结果时使用
  • JSON字符串:用于响应XMLHttpRequest
  • 文件下载:用户可以从您的应用中下载一些数据(可以是文件内容或即时生成的字符串)
  • HTML内容:用于以格式化方式响应,稍后输出到屏幕(例如,命令生成产品列表)

这是一个简单的框架,您可能会说生成视图内容不应与计算混合。您是对的,但目标是创建一个包含基本功能的简单框架。

创建命令类

常见情况

要响应命令(如GET/POST请求),只需创建一个以命令名称命名的类,并从Command类继承即可

namespace Myapp\Commands;

use \Nettools\Simple_Framework\Command;
use \Nettools\Simple_Framework\Request;
use \Nettools\Simple_Framework\Application;


class Test extends Command
{
    public function execute(Request $req, Application $app)
    {
        return $this->returnHTML("Command <b>'test'</b> is called with parameter '{$req->param}' !");
    }
}

如您所猜,此命令返回HTML内容。此内容尚未输出到屏幕。这是在页面模板中稍后完成的。

返回的字符串将包含查询字符串的'param'值,可通过Request $req对象访问。此对象填充了所有GET/POST参数,作为PHP属性。数据在设置到Request对象之前被清理。

如果您想响应XMLHttpRequest,返回以下任一线的JSON值。Command类的returnJson()方法足够智能,允许不同数据类型,并在内部将它们转换为JSON格式的字符串。

return $this->returnJson('{"value":"'. $req->param . '"}');        // string
return $this->returnJson(array('value' => $req->param));           // associative array
return $this->returnJson((object)array('value' => $req->param));   // object litteral

要使用下载响应命令,使用returnFileDownload()returnStringDownload(),具体取决于数据是否包含在文件中或即时生成的字符串

// downloading a file with Mimetype 'text/plain', the browser will suggest the name 'test.txt' as filename with 'my file content' as data downloaded.
return $this->returnStringDownload("my file content", 'test.txt', 'text/plain'); 

// downloading a file from path '/tmp/compute.bin', with Mimetype 'application/octet-stream' ; when saved, the browser will suggest 'data.bin' as filename
return $this->returnFileDownload('/tmp/compute.bin', 'data.bin', 'application/octet-stream');

处理文件上传

如果您想处理用户上传的文件,请使用Request类的getFileUpload()方法获取描述已上传文件的特定FileUploadRequest对象

namespace Myapp\Commands;

use \Nettools\Simple_Framework\Command;
use \Nettools\Simple_Framework\Request;
use \Nettools\Simple_Framework\Application;

class Upload extends Command
{
    public function execute(Request $req, Application $app)
    {
        // the input named 'upload' should always be in the request, even if no file has been submitted.
        // $f will contain a FileUploadRequest object.
        if ( $f = $req->getFileUpload('upload') )
            // if a file has been submitted
            if ( $f->uploaded() )
            {
                // we erase the temp file, this is just a test
                unlink($f->tmp_name);
                return $this->returnString('File was sent');
            }
            
            // if no file has been submitted
            else if ( $f->no_file() )
                return $this->returnString('The user has not uploaded a file');
            
            // unknown other error
            else
                return $this->returnString('Upload error');
        else
            return $this->returnString('Field upload does not exist');
    }
}

发送命令

要执行之前定义的命令,您必须向应用的URI发送HTTP请求。如果'index.php'是应用文件

index.php?cmd=test&param=hello+world

如你所见,命令的名称应设置在cmd URI查询字符串参数中。其他参数旨在在命令执行期间使用(如$req->param用于param查询字符串值)。

请求也可以通过POST动词或JavaScript中的XMLHttpRequest发送。

本页上的前两个示例(HTML响应和XMLHttpResponse)将输出:

命令 <b>'test'</b> 使用参数 'hello world' 被调用!

并且

{"value":"hello world"}

启动应用程序以处理请求

当使用HTTP请求(如 index.php?cmd=test&param=hello+world)向应用程序发送命令时,您需要启动应用程序框架,以便它可以处理请求并从命令执行返回输出。

<?php
namespace Myapp;

use \Nettools\Simple_Framework\WebApplication;
use \Nettools\Simple_Framework\Registry;


// créer l'application
$app = new WebApplication(
        // user namespace for commands
        '\\Myapp\\Commands', 
    
        // registry for config data
        new Registry()
    );

// launch app and get the returned result in $output
$output = $app->run();
?>
<html>
  <body>
  Command output as HTML or php value : <?php echo $output; ?>.
  </body>
</html>

创建了一个 WebApplication 对象,以便应用程序可以运行。其第一个参数是要查找命令类的命名空间(请参阅此处的前几个示例,命令的命名空间为 Myapp\Commands),第二个参数是用于存储配置数据的 Registry 对象(为了简化示例,该注册表为空;对于此测试,我们不需要任何配置数据)。如果需要处理敏感的配置数据,创建您的注册表(使用 Config\ConfigObjectJsonFileJson),然后将其封装在顶级 Config\PrivateConfig 注册表中(请参阅具体示例文件)。

然后,在 Application $app 对象上调用 run() 方法:在 Myapp\Commands 命名空间中搜索由 cmd 查询字符串参数引用的命令,调用它,并将结果设置到 $output 中。

对于Web应用程序(这可能是情况),一些返回值应该立即发送到浏览器(JsonDownloadFileDownloadStringDownload);是否输出或处理该输出(根据返回值类型)的过程由 ReturnedValuesOutput 子命名空间中的类处理。如果找到了名为 WebController_xxxx 的类(其中 xxxx 表示返回值类(DownloadJson 等),则此类负责输出。如果没有找到特定返回值的类,则不会向浏览器输出,并且值将通过 $app->run() 返回。

请参阅 Nettools\Simple_FrameworkReturnedValues 子命名空间中的类,以获取可接受的返回值完整列表(所有继承自 ReturnedValues\Value)。

在其他情况下,命令返回一个值,该值从 $app->run() 执行中获取。在大多数情况下,这将是一些HTML内容或原始PHP类型(字符串、整数等),您可以在稍后的页面模板中包含或使用它:`echo $output` 将 ReturnedValues\Value 对象转换为字符串。

处理错误情况和异常

当发生异常或您故意使命令失败时,框架将执行一些特定操作。

异常:框架将处理它们

在代码执行期间抛出(并且未被您的代码捕获)的异常在 Controller 对象的 run() 方法中被捕获,并显示一个包含所有必要调试数据的特定屏幕(并且脚本停止)。为了您的信息,这些调试数据是由 Nettools\Core\ExceptionHandlers\SimpleExceptionHandler 格式的(您可以通过参考 Nettools\Core 包来读取更多文档:http://net-tools.ovh/api-reference/net-tools/Nettools/Core/ExceptionHandlers.html)。

您可以为异常设置另一个异常处理器(例如,您不想在屏幕上显示调试数据,而是希望通过电子邮件将调试数据发送给网络管理员);要这样做,当创建 $app 对象时,创建一个名为 appcfgRegistry,并将其 application->exceptionHandler 的值设置为您的选择(但是,它必须继承自 Nettools\Core\ExceptionHandlers\ExceptionHandler,例如 Nettools\Core\ExceptionHandlers\PublicExceptionHandler,它将在屏幕上显示有关异常的简短消息,而没有调试数据;调试数据将作为电子邮件正文和堆栈跟踪的附件发送到 postmaster@yourdomain.com)。

错误情况:失败

有时,您想表示一个命令执行未成功。为此,在您的命令 execute 调用期间,请使用适当的错误消息调用 $this 上的 fail()

class Failed extends Command
{
    public function execute(Request $req, Application $app)
    {
        $this->fail('Something went wrong');
    }
}

然后应用程序控制器将处理错误。

  • 如果请求是通过 GET/POST 发送的,则 Applicationrun() 方法将返回一个具有不成功状态的 ReturnedValues\StringValue 对象。您需要通过调用返回值的 isSuccessful() 方法来检测不成功的答案并进行适当的处理:$output = $app->run(); if (!$output->isSuccessful()) echo "error : " . $output;

  • 如果请求是通过 XMLHttpRequest 发送的,则 Applicationrun() 方法(实际上,它是 Controller 对象的 run() 方法)将自动在 stdout 输出一个 Json 字符串并停止脚本:{"statut":false,"message":"出了点问题"}

如果您想用非字符串的错误反馈来回答,您不能使用 fail 机制。然而,您可以用一个具有不成功状态的反回值来回应命令;Command 类的所有 returnXXX 方法都有一个第二个参数来设置执行状态(默认为成功/true)。

class ErrorOccured extends Command
{
    public function execute(Request $req, Application $app)
    {
        return $this->returnPHP(array('msg'=>'Error message', 'line'=>134, 'severity'=>4), false);
    }
}

安全功能

该框架可以完全不带安全功能使用(除了请求被净化之外),或者配置为发送包含特殊计算令牌的请求以识别用户(从而阻止未经授权的请求代表其他用户进行)。

令牌是通过一个秘密(需要在 appcfg 注册表中配置,在 controller->userSecurityHandlers 安全处理程序数组中)和请求中的当前用户 ID(可以是任何请求参数;默认情况下,是 i 参数)创建的。它作为 h 参数(默认情况下,但也可以命名为其他任何名称)与其他参数一起传递。请参阅相应的示例以了解用例。

基于令牌的安全功能 防止黑客在不被授权(登录)的情况下发布其他用户 ID 的请求,因为他们不知道如何计算令牌值(不知道秘密或哈希过程)。

然而,它 不能 防止请求被多次发布(令牌不是一个一次性值),也不能防止请求容易受到 CSRF 攻击。

在未来的版本中,可能会实现 CSRF 安全功能和一次性令牌。

PHPUnit

要使用 PHPUnit 进行测试,请将 -c 配置选项指向 /phpunit.xml 配置文件。