biensure / signal
An API Swiss Army Knife, extend this Signal class with methods and create it
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- phpunit/phpunit: ^9.6
This package is not auto-updated.
Last update: 2025-05-08 20:15:48 UTC
README
An API Swiss Army Knife
Extend this Signal class with methods and do "new YourSignalClassExtension()"
Name your methods like "GETcontacts", "POSTlogin" and all of them will be callable: GET /contacts, POST /login
Use Signal class functions to read a JSON/XML/TEXT body() into an array and ("ANSWER") to any request in a vew lines of PHP
Run
- Please make sure you have php 7.4 or higer and composer installed (see https://getcomposer.org)
Method 1
Clone the repo to get the files and run composer install
# clone and change dir
git clone https://gitlab.com/biensure/signal && cd ./signal && composer install
Create a file named index.php with the following content
// include autoload
require __DIR__ . '/vendor/autoload.php';
// extend Biensure\Signal
class SignalExtensionExample extends Biensure\Signal
{
public function GET()
{
self::_("<h1>HOME</h1>\n<a href='./api'>API info</a>", 200, "HTML");
}
public function GETapi()
{
self::_($this->getApiArray());
}
}
// create your extension
new SignalExtensionExample();
Create a file named .htaccess with the following content:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
For shared hosting
Use your ftp client to upload your files to your ../public, ../htdocs folder and visit your website
For local apache
Place the files of your project folder to in your /var/www/html folder and open your browser to http://localhost
Method 2
Create your own project, do composer require and use php build-in webserver
# composer
composer require biensure/signal
# run php build in server to run the example
php -S localhost -t ./signal/tests/ ./signal/tests/index.example
# or create an index.php file as described in "Method 1" an do
php -S localhost -t ./ ./index.php
Open your browser to http://localhost
Subdirectory installation
When moving your project folder to a subdirectory like: "/v1/".
It is necessary to define the static $BASE_PATH variable in your extension class
...
// extend Biensure\Signal
class SignalExtensionExample extends Biensure\Signal
{
public static $BASE_PATH = "/v1/";
...
For shared hosting and apache please change your .htaccess file to this:
RewriteEngine On
RewriteBase /v1/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
Usage
These examples are served by the php build in server, see above "Method 2"
GET / - HOME
Create a file named index.php and extend the Biensure\Signal class as described in "Method 1" above.
Check if your home page displays probably: "HOME" and a link "API info".
GET /info - URI to function
Add this to the extention class:
public function GETinfo(int $i, string $s = "some", ...$uri)
{
$o = "<h1>GETinfo</h1>";
$o .= "<pre>";
$o .= "\n headers> ". var_export(self::_headers(), true);
$o .= "\n i> ". var_export($i, true);
$o .= "\n s> ". var_export($s, true);
$o .= "\n uri> ". var_export($uri, true);
$o .= "\n vars> ". var_export(self::_vars(), true);
$o .= "</pre>";
self::_($o, 200, "HTML"); // "HTML" is needed because the default is "JSON"
}
- Open http://localhost/info/12 points to your extended Biensure/Signal class the function GETinfo injects "12" as required parameter
- Try http://localhost/info/text and see the error, this is because $i is defined to be an (int). Watch out! - definition of (array) is not supported.
- Vist http://localhost/info/12/other and see that the default value of $s is set to "other"
- Now adding more URI will create and grow the (variadic) $uri.
- Overload of arguments is possible because of the (variadic) ...$uri variable defined in the function.
- Removing this variable from the function will throw an "404 - Not Found" on visiting any link longer then: http://localhost/info/12/other/
GET /login, POST /login - Flag authorization
Add this to the extention class:
public function GETlogin()
{
$flagStatus = self::getSessionFlag();
if ( $flagStatus <= 0 ) {
$o = '<h3>Login</h3>';
$o .= '<form method="POST" action="login">';
$o .= '<div>User: </div><input name="user" type="text"> # john<br>';
$o .= '<div>Password: </div><input name="password" type="text"> # doit<br><br>';
$o .= '<input type="submit" value="submit">';
$o .= '</form>';
} else {
$o = '<h3>Logout</h3>';
$o .= '<form method="POST" action="logout">';
$o .= '<input type="submit" value="submit">';
$o .= '</form>';
}
self::_($o, 200, "HTML");
}
public function POSTlogin()
{
$vars = self::_colOrCrash( ["user", "password"], array_merge(self::_vars(), self::_body()) );
if ( $vars['user'] == "john" && $vars['password'] == "doit" ) {
self::setSessionFlag(100);
$o = ["success" => true];
} else
$o = ["success" => false];
self::_($o);
}
public function GETlogstatus()
{
$flagStatus = self::getSessionFlag();
self::_(["logstatus" => $flagStatus]);
}
public function GETsecret()
{
self::flag(100); // authorization check
self::_("go for heavenly treasure");
}
- Surf to http://localhost/logstatus and see the flagStatus is 0
- Surf to http://localhost/login and login as "john", "doit"
- Surf to http://localhost/logstatus and see the flagStatus is 100
- Surf to http://localhost/secret and see the secret
The Flag functionality is there to keep unauthorized users to see the /secret.
Logging in sets the Flag authorization level to 100 and gives the user privilege to see the /secret.
- self::getSessionFlag() function in GETlogin gets the current value of the flag variable in the session
- self::_vars() function reads the _GET and _POST variables
- self::_body() reads any body variables ("JSON" by default, but can be "XML" or "TEXT" lines too) into an array. Attention! this function can only be called once.
- self::_colOrCrash( ["user", "password"], array_merge(self::_vars(), self::_body()) ) function in POSTlogin reads "user" and "password" or throws a 422
- self::_colOrNull() is an alternative to _colOrCrash() that reads variables by name, but returns NULL for unfound variables.
- self::setSessionFlag(100) in POSTlogin sets the Flag to 100 in session variable
- self::flag(100) function in GETsecret checks if the session contains a flag with at least a value of 100 else it throws a 404
PATCH example using curl
Add this to the extention class:
public function PATCHschema()
{
self::flag(100); // authorization check
$vars = self::_colOrNull(["name", "schema"], self::_body()); // get "name" and "schema"
self::_(["name" => $vars['name'], "schema" => $vars['schema']]);
}
Then use curl to login and save the session cookie
curl -c cookies.txt -H 'Content-Type: application/json' -d '{ "user":"john", "password": "doit"}' -X POST http://localhost/login
See that you ar logged in while using that session cookie:
curl -b cookies.txt -H 'Content-Type: application/json' -X GET http://localhost/logstatus
And do the PATCH schema with session cookie
curl -b cookies.txt -H 'Content-Type: application/json' -d '{ "name": "test", "schema": { "type" : "string" } }' -X PATCH http://localhost/schema
Try the same thing without the session cookie
curl -H 'Content-Type: application/json' -d '{ "name": "test", "schema": { "type" : "string" } }' -X PATCH http://localhost/schema
GET /api
Add the following PHP Documentation to your functions:
/**
* Shows the API information
*
* @return JSON string
*/
public function GETapi()
{
self::_($this->getApiArray());
}
- Opening your browser to http://localhost/api will show you an JSON formatted description of the total API.
- Automatically all PHP Documentation of the functions is reflected into this view.
Configuration
To configure your API, add/override the following static variables:
...
class SignalExtensionExample extends Biensure\Signal
{
public static $BASE_PATH = ""; // "/v1/", "/tests/" or any project subfolder your index.php is placed
public static $SESSION_FLAG_NAME = "_BIENSURE_SIGNAL_FLAG";
public static $TYPE = "JSON"; // standard communication type: "JSON", HTML", "TEXT", "XML", "MARKDOWN" or "RAW"
public static $METHODS = ["GET", "DELETE", "CONNECT", "HEAD", "OPTIONS", "TRACE", "PATCH", "POST", "PUT"]; // possible HTTP methods
public static $HTML_HEAD = '<!DOCTYPE html><html lang="en"><head><title>'.__CLASS__.'</title><link rel="stylesheet" href="https://unpkg.com/sakura.css/css/sakura.css"></head><body><div>';
public static $HTML_FOOT = '</div></body></html>'; // override both HTML_HEAD and HTML_FOOT with empty '' if unwanted
...
Issues
- [ ] [Issues](https://gitlab.com/biensure/signal/-/issues)
License
MIT
Project status
In development, but tested and in production for my projects like https://gitlab.com/biensure/pitbox