Skip to content
Merged
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
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# PHPapp Framework

**PHPapp** is a lightweight PHP framework designed for quick and efficient web application development. It follows the MVC (Model-View-Controller) architecture and provides core components for database interaction, session management, request handling, and more.
**PHPapp** is a lightweight PHP framework designed for quick and efficient web application development. It follows the MVC (Model-View-Controller) architecture and provides core components for data management, routing, and user interaction.

> [@and-ri](https://github.com/and-ri):
> Hello everyone! I am very excited to share with you a version of my PHP framework. Maybe it is far from such giants as Laravel or Yii, but it has become very convenient for me. Especially for quick deployment of small web applications or prototypes.
> Hello everyone! I am very excited to share with you a version of my PHP framework. Maybe it is far from such giants as Laravel or Yii, but it has become very convenient for me. Especially for quick prototyping and small applications.
>
> I will be happy for any contribution :)

## Features

- **MVC Architecture:** Clean separation of concerns with models, views, and controllers to organize code logically.
- **Core Components:** Includes essential libraries for handling sessions, database connections, request processing, and URL routing.
- **Migration System:** Built-in system for managing database schema changes and versioning.
- **Installer:** Interactive installer for quick setup, including `.env` generation, Composer installation, and database migration execution.
- **Easy to Install and Configure:** Minimal setup required for developers to get started quickly.

## Requirements

- PHP 8+
Expand All @@ -39,7 +41,9 @@
composer install
```

4. Create `.env` file
4. Run the installer:
Open `http://yourdomain.com/installer.php` in your browser and follow the on-screen instructions to set up the database and configuration.

5. Done!

## Core Components
Expand All @@ -55,7 +59,7 @@
- **app.php**: Manages the application lifecycle, including initialization and configuration.
- **db.php**: Provides methods for database queries and connection handling.
- **env.php**: Handles environment variables and configuration settings.
- **google_auth.php**: This file handles the Google authentication process for the application.
- **google_auth.php**: Handles the Google authentication process for the application.
- **language.php**: Loads and manages language files for multi-language support.
- **load.php**: Loads models and controllers dynamically.
- **pagination.php**: Provides simple pagination functionality.
Expand All @@ -65,6 +69,11 @@
- **staticfile.php**: Serves static files (CSS, JS, images).
- **url.php**: Generates URLs and manages routing.

### New Features

- **Migration System:** Manage database schema changes with ease. Use `php migrate.php migrate` to apply migrations, `php migrate.php rollback` to undo the last migration, and `php migrate.php status` to check migration status.
- **Interactive Installer:** Quickly set up your application by providing database and web configuration details in a user-friendly web installer.

## License

This project is licensed under the MIT License.
This project is licensed under the MIT License.
88 changes: 88 additions & 0 deletions migrate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

require_once 'core/library/db.php';

$db = new Db(null); // Initialize the database connection

$command = $argv[1] ?? null;

switch ($command) {
case 'migrate':
migrate($db);
break;

case 'rollback':
rollback($db);
break;

case 'status':
migrationStatus($db);
break;

default:
echo "Usage: php migrate.php [migrate|rollback|status]\n";
break;
}

function migrate($db) {
echo "Running migrations...\n";

// Ensure migrations table exists
$db->query("
CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
migration VARCHAR(255),
applied_at DATETIME
)
");

$appliedMigrations = array_column(
$db->query("SELECT migration FROM migrations", true),
'migration'
);

$files = glob(__DIR__ . '/migrations/*.php');
foreach ($files as $file) {
$migrationName = basename($file, '.php');
if (!in_array($migrationName, $appliedMigrations)) {
require_once $file;
$migration = new Migration();
$migration->up($db);
$db->query("INSERT INTO migrations (migration, applied_at) VALUES ('$migrationName', NOW())");
echo "Applied: $migrationName\n";
}
}
}

function rollback($db) {
echo "Rolling back last migration...\n";

$lastMigration = $db->query("SELECT migration FROM migrations ORDER BY id DESC LIMIT 1")[0]['migration'] ?? null;

if ($lastMigration) {
require_once __DIR__ . "/migrations/$lastMigration.php";
$migration = new Migration();
$migration->down($db);
$db->query("DELETE FROM migrations WHERE migration = '$lastMigration'");
echo "Rolled back: $lastMigration\n";
} else {
echo "No migrations to roll back.\n";
}
}

function migrationStatus($db) {
echo "Migration status:\n";

$migrations = $db->query("SELECT migration, applied_at FROM migrations ORDER BY applied_at", true);
foreach ($migrations as $migration) {
echo "Applied: {$migration['migration']} at {$migration['applied_at']}\n";
}

$files = glob(__DIR__ . '/migrations/*.php');
foreach ($files as $file) {
$migrationName = basename($file, '.php');
if (!in_array($migrationName, array_column($migrations, 'migration'))) {
echo "Pending: $migrationName\n";
}
}
}
11 changes: 11 additions & 0 deletions migrations/template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

class Migration {
public function up($db) {
// Add schema changes (e.g., CREATE TABLE) here
}

public function down($db) {
// Revert schema changes (e.g., DROP TABLE) here
}
}
8 changes: 7 additions & 1 deletion www/index.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<?php

// Check if .env file exists
if (!file_exists(__DIR__ . '/../.env')) {
header('Location: /installer.php');
exit;
}

// Include config files
require_once __DIR__ . '/../config/directories.php';
require_once DIR_CONFIG . 'web.php';

// Run application
require_once DIR_CORE . 'bootstrap.php';
require_once DIR_CORE . 'bootstrap.php';
105 changes: 105 additions & 0 deletions www/installer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Get form data for database
$dbHost = $_POST['db_host'] ?? 'localhost';
$dbName = $_POST['db_name'] ?? 'database';
$dbUser = $_POST['db_user'] ?? 'root';
$dbPassword = $_POST['db_password'] ?? '';

// Get form data for web config
$useSSL = isset($_POST['use_ssl']) ? true : false;
$domain = $_POST['domain'] ?? $_SERVER['HTTP_HOST'];
$defaultLanguage = $_POST['default_language'] ?? 'en';

// Generate .env file
$envContent = "DB_HOST=\"$dbHost\"\nDB_NAME=\"$dbName\"\nDB_USER=\"$dbUser\"\nDB_PASS=\"$dbPassword\"\n";
file_put_contents(__DIR__ . '/../.env', $envContent);

// Generate web.php config
$webConfigContent = "<?php\n\n";
$webConfigContent .= "define('SSL', " . ($useSSL ? 'true' : 'false') . ");\n";
$webConfigContent .= "define('DOMAIN', '$domain');\n";
$webConfigContent .= "define('DEFAULT_LANGUAGE', '$defaultLanguage');\n";
$webConfigContent .= "define('SESSION_NAME', 'PHPAPPSESSID');\n\n";
$webConfigContent .= "define('URL_WEBSITE', (SSL ? 'https://' : 'http://') . DOMAIN . '/');\n";
$webConfigContent .= "define('URL_STATIC', URL_WEBSITE . 'static/');\n";
file_put_contents(__DIR__ . '/../config/web.php', $webConfigContent);

// Check if composer.phar exists
if (!file_exists(__DIR__ . '/../composer.phar')) {
// Download composer.phar
file_put_contents('composer-setup.php', file_get_contents('https://getcomposer.org/installer'));
exec('php composer-setup.php', $output, $returnVar);
unlink('composer-setup.php');
if ($returnVar !== 0) {
die('Error downloading Composer: ' . implode("\n", $output));
}
}

// Run composer install
exec('php ' . __DIR__ . '/../composer.phar install', $output, $returnVar);
if ($returnVar !== 0) {
die('Error installing dependencies: ' . implode("\n", $output));
}

// Run database migrations
exec('php ' . __DIR__ . '/../migrate.php migrate', $output, $returnVar);
if ($returnVar !== 0) {
die('Error running migrations: ' . implode("\n", $output));
}

echo 'Installation complete. Reload the page.';
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHPapp Installer</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="mt-5">PHPapp Installer</h1>
<form method="POST" class="mt-4">
<div class="bg-light p-4 mb-4">
<h3>Database Configuration</h3>
<div class="mb-3">
<label for="db_host" class="form-label">Database Host</label>
<input type="text" class="form-control" id="db_host" name="db_host" required value="localhost">
</div>
<div class="mb-3">
<label for="db_name" class="form-label">Database Name</label>
<input type="text" class="form-control" id="db_name" name="db_name" required value="database">
</div>
<div class="mb-3">
<label for="db_user" class="form-label">Database User</label>
<input type="text" class="form-control" id="db_user" name="db_user" required value="root">
</div>
<div class="mb-3">
<label for="db_password" class="form-label">Database Password</label>
<input type="password" class="form-control" id="db_password" name="db_password" placeholder="<password>" value="">
</div>
</div>
<div class="bg-light p-4 mb-4">
<h3>Web Configuration</h3>
<div class="mb-3">
<label for="domain" class="form-label">Domain</label>
<input type="text" class="form-control" id="domain" name="domain" value="<?php echo $_SERVER['HTTP_HOST']; ?>" required>
</div>
<div class="mb-3">
<label for="default_language" class="form-label">Default Language</label>
<input type="text" class="form-control" id="default_language" name="default_language" value="en" required>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="use_ssl" name="use_ssl">
<label class="form-check-label" for="use_ssl">Use SSL (HTTPS)</label>
</div>
</div>
<button type="submit" class="btn btn-primary btn-lg">Install</button>
</form>
</div>
</body>
</html>