Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
APP_NAME=APP_NAME
APP_NAME="Micro App"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:4000
TIME_ZONE=Asia/Dhaka
APP_LOCALE=en

TIME_ZONE=UTC

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=
DB_USERNAME=root
DB_PASSWORD=
DB_SOCKET=
15 changes: 15 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
APP_NAME="Micro App"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost:4000
APP_LOCALE=en

TIME_ZONE=UTC

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=root
DB_PASSWORD=
DB_SOCKET=
10 changes: 7 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/vendor
/vendor/
.env
.phpunit.result.cache
/.vscode
.composer.lock
/.vscode/
/.idea/
composer.lock
/storage/logs/*.log
/database/*.sqlite
*.DS_Store
10 changes: 5 additions & 5 deletions app/web/controller/WelcomeController.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<?php

declare(strict_types=1);

namespace app\web\controller;

use system\controller\Controller;

class WelcomeController extends Controller
{


public function index()
public function index(): void
{
//return view('welcome');
$this->view('welcome');
}
}
}
25 changes: 22 additions & 3 deletions app/web/middleware/Middleware.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
<?php

declare(strict_types=1);

namespace app\web\middleware;

/**
* Example base middleware.
*
* Create your own middleware classes in app/web/middleware/ and implement
* the handle() method. Register them on individual routes or route groups:
*
* Route::get('/admin', [AdminController::class, 'index'], middleware: [AuthMiddleware::class]);
*
* Route::group('/admin', function () {
* Route::get('/dashboard', [AdminController::class, 'dashboard']);
* }, middleware: [AuthMiddleware::class]);
*/
class Middleware
{
public function handle()
/**
* Execute before the route handler.
*
* Call abort() or redirect() to short-circuit the request.
*/
public function handle(): void
{
// Do something before the request is handled
// Example: abort(403) if user is not authenticated.
}
}
}
90 changes: 80 additions & 10 deletions boot/bootstrap.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,88 @@
<?php

/******************* App initiallize *********************/
declare(strict_types=1);

// ─── Output buffering ────────────────────────────────────────────────────────
ob_start();
session_start();
require_once __DIR__ . "/../vendor/autoload.php";

// ─── Session ─────────────────────────────────────────────────────────────────
if (session_status() === PHP_SESSION_NONE) {
session_start();
}

// ─── Autoloader (also loads system/helper/global.php via composer `files`) ───
require_once __DIR__ . '/../vendor/autoload.php';

// ─── Environment ─────────────────────────────────────────────────────────────
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->safeLoad();
if ($_ENV["APP_DEBUG"] === 'true') {
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();

// ─── Error / exception handling ──────────────────────────────────────────────
if (env('APP_DEBUG') === true) {
// Pretty error pages in development (requires filp/whoops in require-dev)
if (class_exists(\Whoops\Run::class)) {
$whoops = new \Whoops\Run();
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler());
$whoops->register();
} else {
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
}
} else {
ini_set('display_errors', 0);
// Production: suppress display, log to file, show friendly error pages
ini_set('display_errors', '0');
ini_set('log_errors', '1');

$logDir = APP_ROOT . 'storage/logs/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}

ini_set('error_log', $logDir . 'error.log');

set_exception_handler(static function (\Throwable $e) use ($logDir): void {
$status = $e instanceof \system\exception\HttpException
? $e->getStatusCode()
: 500;

// Log everything except expected HTTP errors below 500
if ($status >= 500) {
error_log(sprintf(
'[%s] %s in %s:%d',
date('Y-m-d H:i:s'),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
), 3, $logDir . 'error.log');
}

http_response_code($status);

$viewFile = defined('VIEWS_PATH') ? VIEWS_PATH . "{$status}.php" : null;

if ($viewFile !== null && file_exists($viewFile)) {
include $viewFile;
} else {
echo "<h1>{$status} Error</h1>";
}

exit();
});
}

// ─── Timezone ────────────────────────────────────────────────────────────────
$timezone = (string) env('TIME_ZONE', 'UTC');

if (!date_default_timezone_set($timezone)) {
date_default_timezone_set('UTC');
}
date_default_timezone_set($_ENV['TIME_ZONE']);

// ─── Security headers ────────────────────────────────────────────────────────
\system\http\Response::withSecurityHeaders();

// ─── Routes ──────────────────────────────────────────────────────────────────
require_once APP_ROOT . 'routes/web.php';
\system\router\Route::any('/404', '404');

// ─── Dispatch ────────────────────────────────────────────────────────────────
\system\router\Route::dispatch();
59 changes: 34 additions & 25 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
{
"name": "grayphp/micro",
"description": "PHP micro Framework.",
"description": "A lightweight, production-grade PHP micro framework.",
"keywords": ["php", "framework", "micro", "router", "mvc"],
"type": "project",
"autoload": {
"files": [
"system/helper/global.php"
],
"psr-4": {
"system\\": "system/",
"config\\": "config/",
"app\\": "app/",
"helper\\": "app/helper/"
}
},
"require-dev": {
"filp/whoops": "^2.14",
"phpunit/phpunit": "^9.5.8"
},
"license": "MIT",
"authors": [
{
"name": "Sharif",
"email": "developersharif@yahoo.com"
}
],
"config": {
"optimize-autoloader": true,
"prepend-autoloader": false,
"platform-check": false
},
"require": {
"simple-crud/simple-crud": "^7.5",
"php": ">=8.2",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-pdo": "*",
"simple-crud/simple-crud": "^7.5",
"vlucas/phpdotenv": "^5.5",
"phpmailer/phpmailer": "^6.6",
"nesbot/carbon": "^2.62.1",
"psr/simple-cache": "^1.0|^2.0|^3.0"
}
"nesbot/carbon": "^3.0|^2.72",
"psr/simple-cache": "^3.0"
},
"require-dev": {
"filp/whoops": "^2.15",
"phpunit/phpunit": "^11.0"
},
"autoload": {
"files": [
"system/helper/global.php"
],
"psr-4": {
"system\\": "system/",
"config\\": "config/",
"app\\": "app/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}
13 changes: 9 additions & 4 deletions config/app.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<?php

namespace config;
declare(strict_types=1);

/*** Under Development ***/
return [
'name' => env('APP_NAME', 'Micro Framework'),
];
'name' => env('APP_NAME', 'Micro Framework'),
'env' => env('APP_ENV', 'production'),
'debug' => env('APP_DEBUG', false),
'url' => env('APP_URL', 'http://localhost'),
'timezone' => env('TIME_ZONE', 'UTC'),
'locale' => env('APP_LOCALE', 'en'),
'charset' => 'UTF-8',
];
36 changes: 23 additions & 13 deletions config/database.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
<?php

namespace config;
declare(strict_types=1);

return [
'default' => env('DB_CONNECTION', 'mysql'), // default connection mysql

/*
|--------------------------------------------------------------------------
| Default database connection
|--------------------------------------------------------------------------
| Supported values: "mysql" | "sqlite"
*/
'default' => env('DB_CONNECTION', 'mysql'),

'connections' => [

'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', DATABASE_PATH . 'database.sqlite')
'driver' => 'sqlite',
'database' => env('DB_DATABASE', DATABASE_PATH . 'database.sqlite'),
],

'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', ''),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', ''),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4'
'charset' => 'utf8mb4',
],
]

];
],

];
Empty file added database/.gitkeep
Empty file.
Loading