Skip to content

gonoff/azframework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AzFramework

A lightweight, zero-dependency PHP MVC framework built for rapid application development.

📁 What's in This Repository?

This repository contains:

  1. The Framework (src/) - The core AzFramework code you'll use
  2. A Working Demo (app/, config/, public/) - Shows the framework in action - you can test it right now!
  3. Project Template (skeleton/) - A clean starting point for your own projects

Quick Test: Visit http://localhost/azframework/public/ to see the demo working!

To Start Your Own Project: Copy the skeleton/ folder (see Quick Start below)

📖 New to the framework? Read STRUCTURE.md for a beginner-friendly visual guide!

Features

  • Zero Dependencies - Pure PHP, no Composer required
  • MVC Architecture - Clean separation of concerns
  • Active Record ORM - Elegant database abstraction
  • Built-in Authentication - Session management and CSRF protection
  • Middleware Support - Route-level middleware
  • Pagination - Built-in pagination with search
  • Environment Configuration - .env file support
  • Dynamic Path System - Deploy in any directory structure
  • Helper Functions - Common tasks made easy
  • Security First - CSRF protection, input sanitization, prepared statements

Requirements

  • PHP 8.0 or higher
  • MySQL 5.7+ or MariaDB 10.2+
  • Apache with mod_rewrite enabled (or nginx equivalent)

Quick Start

Option 1: Test the Demo First (Recommended for Learning)

The demo is already working! Just:

  1. Make sure XAMPP is running
  2. Visit: http://localhost/azframework/public/
  3. You should see the framework working with styled pages
  4. Explore the code:
    • Controllers: app/Controllers/HomeController.php
    • Views: app/Views/home.php
    • Routes: config/routes.php

This helps you understand how the framework works before creating your own project!

Option 2: Start Your Own Project

# 1. Copy the skeleton to your project folder
cp -r azframework/skeleton/* /path/to/myproject/

# 2. Copy framework source into your project
mkdir -p /path/to/myproject/azframework
cp -r azframework/src /path/to/myproject/azframework/

# 3. Set up your .env
cd /path/to/myproject
cp .env.example .env
# Edit .env with your settings

2. Configure Environment

cd myproject
cp .env.example .env

# Edit .env with your configuration
nano .env

Update these values:

APP_NAME="My Application"
APP_URL=http://localhost/myproject
APP_BASE_PATH=/myproject

DB_HOST=127.0.0.1
DB_DATABASE=my_database
DB_USERNAME=root
DB_PASSWORD=your_password

3. Create Database

CREATE DATABASE my_database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

4. Set Permissions

chmod -R 755 storage/
chmod -R 777 storage/logs storage/sessions storage/uploads

5. Configure Apache

Ensure your web server points to the public/ directory, or update .htaccess RewriteBase:

# In public/.htaccess
RewriteBase /myproject/

6. Access Your Application

Visit: http://localhost/myproject/

Framework Structure

azframework/
├── src/
│   ├── Core/
│   │   ├── Database.php      # PDO singleton connection
│   │   ├── Model.php          # Active Record base class
│   │   ├── Controller.php     # Base controller with helpers
│   │   └── Router.php         # Pattern-based router
│   ├── Http/
│   │   ├── Middleware.php     # Middleware interface
│   │   ├── AuthMiddleware.php # Authentication middleware
│   │   └── CsrfMiddleware.php # CSRF protection
│   ├── Support/
│   │   └── helpers.php        # Global helper functions
│   └── bootstrap.php          # Framework initialization
├── config/
│   ├── app.php               # Application config
│   └── database.php          # Database config
├── public/
│   ├── index.php             # Entry point
│   └── .htaccess             # URL rewriting
└── README.md                 # This file

Creating Your First Model

<?php
namespace App\Models;

use AzFramework\Core\Model;

class User extends Model
{
    protected $table = 'users';
    protected $primaryKey = 'user_id';
    protected $fillable = ['username', 'email', 'password', 'role'];

    public function setPassword($password)
    {
        $this->attributes['password'] = password_hash($password, PASSWORD_BCRYPT);
    }

    public function getFullNameAttribute()
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}

Creating Your First Controller

<?php
namespace App\Controllers;

use AzFramework\Core\Controller;
use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        $this->requireAuth();

        $result = (new User())->paginate(
            page: $_GET['page'] ?? 1,
            perPage: 20,
            orderBy: 'created_at DESC'
        );

        $this->view('users/index', [
            'title' => 'Users',
            'users' => $result['data'],
            'pagination' => $result['pagination'],
            'csrf_token' => $this->csrf()
        ]);
    }

    public function store()
    {
        $this->requireAuth();
        $this->verifyCsrf();

        $data = $this->validateAndSanitize($_POST, [
            'username' => 'required|min:3',
            'email' => 'required|email',
            'password' => 'required|min:6'
        ]);

        if ($data === false) {
            return $this->redirect('/users/create');
        }

        $user = new User();
        $user->setPassword($data['password']);
        unset($data['password']);

        if ($user->create($data)) {
            $this->setSuccess('User created successfully');
            $this->redirect('/users');
        } else {
            $this->setError('Failed to create user');
            $this->redirect('/users/create');
        }
    }
}

Model Methods

Finding Records

// Find by primary key
$user = (new User())->find($id);

// Find all with conditions
$users = (new User())->findAll(['role' => 'admin'], 'created_at DESC');

// Query by field
$users = (new User())->where('email', 'LIKE', '%@example.com%');

// Count records
$count = (new User())->count(['role' => 'admin']);

Creating Records

$user = new User();
$user->create([
    'username' => 'john',
    'email' => 'john@example.com',
    'role' => 'user'
]);

// Or use save()
$user = new User();
$user->fill($_POST);
$user->save();

Updating Records

$user = (new User())->find($id);
$user->email = 'newemail@example.com';
$user->update();

// Or update specific fields
$user->update(['email' => 'newemail@example.com']);

Deleting Records

$user = (new User())->find($id);
$user->delete();

Pagination

$result = (new User())->paginate(
    page: 1,
    perPage: 20,
    conditions: ['active' => 1],
    orderBy: 'created_at DESC',
    allowedOrderColumns: ['created_at', 'username', 'email']
);

// Access data
$users = $result['data'];
$pagination = $result['pagination'];

Search and Pagination

$result = (new User())->searchAndPaginate(
    searchTerm: 'john',
    searchFields: ['username', 'email', 'first_name', 'last_name'],
    page: 1,
    perPage: 20
);

Controller Helpers

Authentication

// Require user to be logged in
$this->requireAuth();

// Require specific role
$this->requireRole('administrator');

// Get current user ID
$userId = $_SESSION['user_id'];

CSRF Protection

// Generate token (in view)
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">

// Or use helper
<?= csrf_field() ?>

// Verify token (in controller)
$this->verifyCsrf();

Validation

$data = $this->validateAndSanitize($_POST, [
    'email' => 'required|email',
    'password' => 'required|min:6',
    'age' => 'required|min:1'
]);

if ($data === false) {
    // Validation failed, errors stored in session
    return $this->redirect('/form');
}

Flash Messages

// Set messages
$this->setSuccess('Operation completed successfully');
$this->setError('Something went wrong');

// Display in view
<?php if (isset($_SESSION['success'])): ?>
    <div class="alert alert-success"><?= $_SESSION['success'] ?></div>
    <?php unset($_SESSION['success']); ?>
<?php endif; ?>

Responses

// Render view
$this->view('users/index', ['users' => $users]);

// JSON response
$this->json(['success' => true, 'data' => $users]);

// Redirect
$this->redirect('/dashboard');

// Abort with error
abort(404, 'Page not found');

Helper Functions

// Environment variables
$debug = env('APP_DEBUG', false);

// Generate URLs
$url = base_path('users/123');          // /myproject/users/123
$asset = asset('css/app.css');           // /myproject/assets/css/app.css

// Configuration
$appName = config('app.name', 'My App');

// Session
$userId = session('user_id');

// Request input
$email = request('email');

// HTML escaping
echo e($userInput);

// Dump and die (debugging)
dd($variable, $anotherVar);

// Old input (form repopulation)
<input name="email" value="<?= old('email') ?>">

// CSRF token
<?= csrf_field() ?>
$token = csrf_token();

Routing

Basic Routes

// config/routes.php
return [
    '/' => 'HomeController@index',
    '/about' => 'PageController@about',
    '/contact' => 'ContactController@show',
];

Route Parameters

'/users/{id}' => 'UserController@show',
'/posts/{id}/comments/{comment_id}' => 'CommentController@show',

Parameters are passed to controller methods:

public function show($id)
{
    $user = (new User())->find($id);
    // ...
}

Middleware

Creating Middleware

<?php
namespace App\Middleware;

use AzFramework\Http\Middleware;

class AdminMiddleware implements Middleware
{
    public function handle()
    {
        if (session('user_role') !== 'administrator') {
            abort(403, 'Access denied');
        }
    }
}

Using Middleware (Coming Soon)

Middleware support is built into the router but needs to be configured per route.

Deployment

Production Checklist

  1. Update .env for production
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
APP_BASE_PATH=
  1. Secure file permissions
chmod -R 755 .
chmod -R 700 storage/
chmod 600 .env
  1. Update .htaccess
RewriteBase /
  1. Enable HTTPS Update in .env and ensure certificate is installed.

  2. Database backups Set up automated backups for your database.

Security Best Practices

  1. Never commit .env files - Add to .gitignore
  2. Use prepared statements - Already handled by Model class
  3. Validate all input - Use validateAndSanitize()
  4. CSRF protection - Use verifyCsrf() on POST routes
  5. Hash passwords - Use password_hash() (bcrypt)
  6. Set secure headers - Already in .htaccess
  7. Limit file uploads - Configure in config/app.php

Common Patterns

Form with Validation

// Controller
public function create()
{
    $this->view('users/form', [
        'csrf_token' => $this->csrf(),
        'user' => null
    ]);
}

public function store()
{
    $this->verifyCsrf();

    $data = $this->validateAndSanitize($_POST, [
        'username' => 'required|min:3',
        'email' => 'required|email'
    ]);

    if ($data === false) {
        return $this->redirect('/users/create');
    }

    $user = new User();
    if ($user->create($data)) {
        $this->setSuccess('User created');
        $this->redirect('/users');
    }
}

Pagination View

<?php foreach ($users as $user): ?>
    <div><?= e($user->username) ?></div>
<?php endforeach; ?>

<?= $this->renderPagination($pagination, base_path('users')) ?>

Extending the Framework

Custom Base Controller

namespace App\Core;

use AzFramework\Core\Controller as BaseController;

class Controller extends BaseController
{
    protected function getCurrentUser()
    {
        if (!isset($_SESSION['user_id'])) {
            return null;
        }
        return (new \App\Models\User())->find($_SESSION['user_id']);
    }
}

Then extend your custom controller:

namespace App\Controllers;

use App\Core\Controller;

class UserController extends Controller
{
    // Your methods
}

Troubleshooting

404 on all routes

  • Check .htaccess RewriteBase matches your deployment path
  • Ensure mod_rewrite is enabled in Apache
  • Verify web server points to public/ directory

CSRF validation failed

  • Check APP_BASE_PATH matches deployment location
  • Verify session is starting properly
  • Check storage/sessions is writable

Database connection failed

  • Verify database credentials in .env
  • Ensure database exists
  • Check MySQL/MariaDB is running

Session not persisting

  • Check storage/sessions permissions (777)
  • Verify session cookie path in bootstrap
  • Check browser cookies are enabled

License

This framework is open-source software. Use it freely for personal or commercial projects.

Support

For issues, questions, or contributions, contact the framework author or check the documentation.


Built with ❤️ for rapid PHP development

About

Lightweight PHP MVC framework for rapid application development.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors