Last active
November 25, 2022 17:49
-
-
Save yusufusta/d6c5dc861efa111808a6025daf9ce925 to your computer and use it in GitHub Desktop.
Proof that PHP works well without any framework.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function redirect(string $url) | |
{ | |
header("Location: $url"); | |
die(); | |
} | |
function json(array $arr) | |
{ | |
die(json_encode($arr)); | |
} | |
function text($text) | |
{ | |
die($text); | |
} | |
class BasicPHPFramework | |
{ | |
/** | |
* Flash messages session key name. | |
* | |
* @var string | |
*/ | |
private string $FLASH = 'FLASH_MESSAGES'; | |
/** | |
* @var array | |
*/ | |
private array $PAGES = []; | |
/** | |
* @var array | |
*/ | |
private array $MIDS = []; | |
/** | |
* @var array | |
*/ | |
private array $CONFIG = []; | |
/** | |
* PDO object. | |
* | |
* @var PDO | |
*/ | |
public PDO $pdo; | |
/** | |
* Router URL matches. | |
* | |
* @var array | |
*/ | |
public array $matches; | |
/** | |
* HTTP status codes helper. | |
* | |
* @var array | |
*/ | |
public array $httpStatusCodes = [100 => "Continue", 101 => "Switching Protocols", 102 => "Processing", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 207 => "Multi-Status", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 306 => "(Unused)", 307 => "Temporary Redirect", 308 => "Permanent Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Timeout", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Request Entity Too Large", 414 => "Request-URI Too Long", 415 => "Unsupported Media Type", 416 => "Requested Range Not Satisfiable", 417 => "Expectation Failed", 418 => "I'm a teapot", 419 => "Authentication Timeout", 420 => "Enhance Your Calm", 422 => "Unprocessable Entity", 423 => "Locked", 424 => "Failed Dependency", 424 => "Method Failure", 425 => "Unordered Collection", 426 => "Upgrade Required", 428 => "Precondition Required", 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 444 => "No Response", 449 => "Retry With", 450 => "Blocked by Windows Parental Controls", 451 => "Unavailable For Legal Reasons", 494 => "Request Header Too Large", 495 => "Cert Error", 496 => "No Cert", 497 => "HTTP to HTTPS", 499 => "Client Closed Request", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout", 505 => "HTTP Version Not Supported", 506 => "Variant Also Negotiates", 507 => "Insufficient Storage", 508 => "Loop Detected", 509 => "Bandwidth Limit Exceeded", 510 => "Not Extended", 511 => "Network Authentication Required", 598 => "Network read timeout error", 599 => "Network connect timeout error"]; | |
/** | |
* BasicPHPFramework constructor. Set the config here. | |
* | |
* @param array $config The config array. | |
* | |
* $config = [ | |
* 'db' => [(string) DSN, (string) Username, (string) Password], | |
* 'assets_folder' => string, | |
* ]; | |
*/ | |
public function __construct($config = []) | |
{ | |
$this->CONFIG = $config; | |
if (!empty($config["db"])) { | |
$this->pdo = new PDO($config["db"][0], $config["db"][1], $config["db"][2]); | |
} | |
if (!empty($config["assets_folder"])) { | |
$assets = $config["assets_folder"]; | |
$this->addPage("GET_ASSETS", "/assets/(.*)", function (self $fw) use ($assets) { | |
$filename = $assets . "/" . $fw->matches[1]; | |
if (!is_file($filename)) { | |
return $this->callHttpResponse(404); | |
} | |
header('Content-Type: ' . $this->mimeContentType($filename)); | |
readfile($filename); | |
die(); | |
}); | |
} | |
if (empty($config["view"])) { | |
$config["view"] = "pages"; | |
} | |
} | |
/** | |
* Add an middleware to the framework. | |
* | |
* @param Closure $function | |
* @return BasicPHPFramework | |
*/ | |
public function add(Closure $function): self | |
{ | |
$this->MIDS[] = [ | |
$function | |
]; | |
return $this; | |
} | |
/** | |
* Add a page to the framework. | |
* | |
* @param string $method | |
* @param string $route | |
* @param Closure $function | |
* @return BasicPHPFramework | |
*/ | |
public function addPage($method, $url, Closure $function): self | |
{ | |
if (is_array($method) && is_array($url)) { | |
foreach ($method as $m) { | |
foreach ($url as $u) { | |
$this->addPage($m, $u, $function); | |
} | |
} | |
return $this; | |
} | |
if (is_array($method)) { | |
foreach ($method as $m) { | |
$this->addPage($m, $url, $function); | |
} | |
return $this; | |
} | |
if (is_array($url)) { | |
foreach ($url as $u) { | |
$this->addPage($method, $u, $function); | |
} | |
return $this; | |
} | |
$this->PAGES[] = [ | |
$method, | |
$url, | |
$function | |
]; | |
return $this; | |
} | |
/** | |
* Run the Framework. | |
* | |
* @return void | |
*/ | |
public function run() | |
{ | |
$status_code = 404; | |
$url = $_SERVER['REQUEST_URI']; | |
foreach ($this->PAGES as $page) { | |
if (!empty($_GET) && strstr($url, "?")) { | |
$url = strstr($url, "?", true); | |
} | |
if (!preg_match("/^" . (str_replace("/", "\/", $page[1])) . "$/m", $url, $matches)) { | |
continue; | |
} | |
$this->matches = $matches; | |
if (!in_array(strtoupper($page[0]), ["*", "GET_ASSETS"]) && $_SERVER['REQUEST_METHOD'] !== strtoupper($page[0])) { | |
$status_code = 405; | |
continue; | |
} | |
$status_code = 200; | |
break; | |
} | |
if ($status_code === 200 && $page[0] === "GET_ASSETS") { | |
return call_user_func($page[2], $this); | |
} | |
foreach ($this->MIDS as $mid) { | |
call_user_func($mid[0], $this, [$status_code, $page]); | |
} | |
if ($status_code === 200) { | |
return call_user_func($page[2], $this); | |
} | |
return $this->callHttpResponse($status_code); | |
} | |
/** | |
* Call the HTTP Response. | |
* | |
* @param int $status_code | |
* @return never | |
*/ | |
public function callHttpResponse($code = 404) | |
{ | |
if (!empty($this->CONFIG["status_codes"][$code])) { | |
call_user_func($this->CONFIG["status_codes"][$code], $this); | |
} else if (array_key_exists($code, $this->httpStatusCodes)) { | |
http_response_code($code); | |
die("<html><head><title>" . $code . " " . $this->httpStatusCodes[$code] . "</title></head><body><h1>" . $code . "</h1><h2>" . $this->httpStatusCodes[$code] . "</h2></body></html>"); | |
} else { | |
http_response_code(500); | |
die("<html><head><title>500 Internal Server Error</title></head><body><h1>500</h1><br><h2>Internal Server Error -- BasicPHPFramework error</h2></body></html>"); | |
} | |
} | |
/** | |
* Get the MIME Content Type. | |
* | |
* @param string $filename | |
* @return string | |
*/ | |
function mimeContentType($filename) | |
{ | |
$mime_types = [ | |
'txt' => 'text/plain', | |
'htm' => 'text/html', | |
'html' => 'text/html', | |
'php' => 'text/html', | |
'css' => 'text/css', | |
'js' => 'application/javascript', | |
'json' => 'application/json', | |
'xml' => 'application/xml', | |
'swf' => 'application/x-shockwave-flash', | |
'flv' => 'video/x-flv', | |
'png' => 'image/png', | |
'jpe' => 'image/jpeg', | |
'jpeg' => 'image/jpeg', | |
'jpg' => 'image/jpeg', | |
'gif' => 'image/gif', | |
'bmp' => 'image/bmp', | |
'ico' => 'image/vnd.microsoft.icon', | |
'tiff' => 'image/tiff', | |
'tif' => 'image/tiff', | |
'svg' => 'image/svg+xml', | |
'svgz' => 'image/svg+xml', | |
'zip' => 'application/zip', | |
'rar' => 'application/x-rar-compressed', | |
'exe' => 'application/x-msdownload', | |
'msi' => 'application/x-msdownload', | |
'cab' => 'application/vnd.ms-cab-compressed', | |
'mp3' => 'audio/mpeg', | |
'qt' => 'video/quicktime', | |
'mov' => 'video/quicktime', | |
'pdf' => 'application/pdf', | |
'psd' => 'image/vnd.adobe.photoshop', | |
'ai' => 'application/postscript', | |
'eps' => 'application/postscript', | |
'ps' => 'application/postscript', | |
'doc' => 'application/msword', | |
'rtf' => 'application/rtf', | |
'xls' => 'application/vnd.ms-excel', | |
'ppt' => 'application/vnd.ms-powerpoint', | |
'odt' => 'application/vnd.oasis.opendocument.text', | |
'ods' => 'application/vnd.oasis.opendocument.spreadsheet', | |
]; | |
$ext = pathinfo($filename, PATHINFO_EXTENSION); | |
if (array_key_exists($ext, $mime_types)) { | |
return $mime_types[$ext]; | |
} elseif (function_exists('finfo_open')) { | |
$finfo = finfo_open(FILEINFO_MIME); | |
$mimetype = finfo_file($finfo, $filename); | |
finfo_close($finfo); | |
return $mimetype; | |
} elseif (function_exists('mime_content_type')) { | |
return mime_content_type($filename); | |
} else { | |
return 'application/octet-stream'; | |
} | |
} | |
/** | |
* Create or get one|all flash messages. | |
* | |
* @param string $name | |
* @param string $message | |
* @param string $type | |
* @return void | |
*/ | |
public function flash(string $name = '', string $message = '', string $type = '') | |
{ | |
if ($name !== '' && $message !== '' && $type !== '') { | |
if (isset($_SESSION[$this->FLASH][$name])) { | |
unset($_SESSION[$this->FLASH][$name]); | |
} | |
$_SESSION[$this->FLASH][$name] = ['message' => $message, 'type' => $type]; | |
return true; | |
} elseif ($name !== '' && $message === '' && $type === '') { | |
if (!isset($_SESSION[$this->FLASH][$name])) { | |
return false; | |
} | |
$msg = $_SESSION[$this->FLASH][$name]; | |
unset($_SESSION[$this->FLASH][$name]); | |
return $msg; | |
} elseif ($name === '' && $message === '' && $type === '') { | |
if (!isset($_SESSION[$this->FLASH])) { | |
return false; | |
} | |
$msg = $_SESSION[$this->FLASH]; | |
unset($_SESSION[$this->FLASH]); | |
return $msg; | |
} | |
} | |
/** | |
* Check array is associative. | |
* | |
* @param array $arr | |
* @return boolean | |
*/ | |
public static function isAssoc(array $arr) | |
{ | |
if (array() === $arr) return false; | |
return array_keys($arr) !== range(0, count($arr) - 1); | |
} | |
/** | |
* Run query and return results. | |
* | |
* @param string $query | |
* @param array $params | |
* @return (PDOStatement|bool)[] | |
*/ | |
public function query(string $query, array $params = []): array | |
{ | |
if (empty($this->CONFIG["db"])) { | |
throw new Exception("No DB connection found. Please set a DB connection in the config array."); | |
} | |
$stmt = $this->pdo->prepare($query); | |
if (empty($params)) { | |
$exec = $stmt->execute(); | |
} else if (self::isAssoc($params)) { | |
foreach ($params as $key => $value) { | |
$stmt->bindValue(($key[0] == ":" ? "" : ":") . $key, $value); | |
} | |
$exec = $stmt->execute(); | |
} else { | |
$exec = $stmt->execute($params); | |
} | |
return [$stmt, $exec]; | |
} | |
/** | |
* Return fetch all results. | |
* | |
* @param string $query | |
* @param array $params | |
* @return array | |
*/ | |
public function fetchAll(string $query, array $params = []): array | |
{ | |
if (empty($this->CONFIG["db"])) { | |
throw new Exception("No DB connection found. Please set a DB connection in the config array."); | |
} | |
[$stmt, $exec] = $this->query($query, $params); | |
return $stmt->fetchAll(PDO::FETCH_ASSOC); | |
} | |
/** | |
* Return fetch one result. | |
* | |
* @param string $query | |
* @param array $params | |
* @return array | |
*/ | |
public function fetch(string $query, array $params = []) | |
{ | |
if (empty($this->CONFIG["db"])) { | |
throw new Exception("No DB connection found. Please set a DB connection in the config array."); | |
} | |
[$stmt, $exec] = $this->query($query, $params); | |
return $stmt->fetch(PDO::FETCH_ASSOC); | |
} | |
/** | |
* Get row count of query. | |
* | |
* @param string $query | |
* @param array $params | |
* @return int | |
*/ | |
public function rowCount(string $query, array $params = []): int | |
{ | |
if (empty($this->CONFIG["db"])) { | |
throw new Exception("No DB connection found. Please set a DB connection in the config array."); | |
} | |
[$stmt, $exec] = $this->query($query, $params); | |
return $stmt->rowCount(); | |
} | |
public function view($file, $data = []) | |
{ | |
$output = ""; | |
$file = __DIR__ . "/" . $this->CONFIG["view"] . "/" . $file . ".php"; | |
if (file_exists($file)) { | |
extract($data); | |
ob_start(); | |
include($file); | |
$output = ob_get_clean(); | |
} else { | |
return $this->callHttpResponse(404); | |
} | |
echo ($output); | |
die; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
güzel