PHPackages                             mzgs/phphelper - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mzgs/phphelper

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mzgs/phphelper
==============

A comprehensive PHP helper library with database, file, login, and utility helpers

079PHP

Since Jan 22Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/mzgs/phphelper)[ Packagist](https://packagist.org/packages/mzgs/phphelper)[ RSS](/packages/mzgs-phphelper/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

PHP Helper Library
==================

[](#php-helper-library)

A comprehensive PHP helper library providing ready-to-use utilities for everyday application tasks.

Installation
------------

[](#installation)

```
composer require mzgs/phphelper:dev-main
```

Requirements
------------

[](#requirements)

- PHP 8.3 or higher

Table of Contents
-----------------

[](#table-of-contents)

1. [AIChat](#aichat) - AI chat integration with OpenAI API
2. [App](#app) - Application environment detection utilities
3. [Arrays](#arrays) - Array manipulation and utilities
4. [AuthManager](#authmanager) - User authentication and session management
5. [Config](#config) - Configuration management with database storage
6. [Countries](#countries) - Country data with flags, ISO codes, and names
7. [DB](#db) - Database abstraction layer for PDO
8. [Date](#date) - Date and time formatting utilities
9. [Files](#files) - File system operations
10. [Format](#format) - Data formatting utilities
11. [Http](#http) - HTTP utilities and client information
12. [Logs](#logs) - Logging system with database storage
13. [PrettyErrorHandler](#prettyerrorhandler) - Enhanced error display
14. [Str](#str) - String manipulation utilities
15. [TwigHelper](#twighelper) - Twig template engine integration
16. [Example index.php](#example-indexphp) - Complete application setup example

---

AIChat
------

[](#aichat)

AI chat integration providing easy interaction with OpenAI-compatible APIs.

### Configuration Options

[](#configuration-options)

```
AIChat::init([
    'base_uri' => 'https://api.openai.com/v1/',  // API base URL
    'endpoint' => 'chat/completions',             // Chat endpoint
    'model' => 'gpt-4o-mini',                     // Default model
    'api_key' => 'your-api-key',                  // API key
    'timeout' => 15.0,                            // Request timeout
    'headers' => [],                              // Additional headers
    'response_format' => null,                    // Response format
    'client_options' => []                        // Additional Guzzle options
]);
```

### Methods

[](#methods)

#### `init(array $config): void`

[](#initarray-config-void)

Configure the AI chat client.

```
// Basic configuration
AIChat::init([
    'api_key' => 'sk-your-openai-api-key',
    'model' => 'gpt-4'
]);

// Advanced configuration with custom headers
AIChat::init([
    'api_key' => 'sk-your-key',
    'model' => 'gpt-3.5-turbo',
    'timeout' => 30.0,
    'headers' => ['User-Agent' => 'MyApp/1.0'],
    'response_format' => 'json_object'
]);
```

#### `setApiKey(?string $apiKey): void`

[](#setapikeystring-apikey-void)

Set or update the API key.

```
AIChat::setApiKey('sk-new-api-key');
```

#### `chat(array $messages, array $payload = []): array`

[](#chatarray-messages-array-payload---array)

Send chat messages to the AI API.

```
// Simple conversation
$messages = [
    ['role' => 'user', 'content' => 'Hello, how are you?']
];
$response = AIChat::chat($messages);
echo $response['choices'][0]['message']['content'];

// With system prompt and temperature
$messages = [
    ['role' => 'system', 'content' => 'You are a helpful assistant.'],
    ['role' => 'user', 'content' => 'Explain quantum physics simply.']
];
$response = AIChat::chat($messages, [
    'temperature' => 0.7,
    'max_tokens' => 150
]);
```

#### `reply(string $prompt, array $payload = [], array $contextMessages = []): string`

[](#replystring-prompt-array-payload---array-contextmessages---string)

Get a direct reply to a prompt.

```
// Simple reply
$answer = AIChat::reply('What is the capital of France?');
echo $answer; // "Paris"

// With context and parameters
$context = [
    ['role' => 'system', 'content' => 'You are a coding tutor.']
];
$answer = AIChat::reply(
    'How do I create a PHP class?',
    ['temperature' => 0.3],
    $context
);
```

#### `reset(): void`

[](#reset-void)

Reset configuration to defaults.

```
AIChat::reset();
```

---

App
---

[](#app)

Application environment detection utilities.

### Methods

[](#methods-1)

#### `isLocal(): bool`

[](#islocal-bool)

Check if the application is running in a local environment.

```
if (App::isLocal()) {
    echo "Running locally";
    // Enable debug mode, detailed logging, etc.
}
```

#### `isCli(): bool`

[](#iscli-bool)

Determine if the script is running from command line.

```
if (App::isCli()) {
    echo "Running from command line";
    // CLI-specific logic
}
```

#### `isProduction(): bool`

[](#isproduction-bool)

Check if running in production environment.

```
if (App::isProduction()) {
    // Production-specific configuration
    ini_set('display_errors', 0);
    error_reporting(0);
}
```

#### `cliMenu(array $options): void`

[](#climenuarray-options-void)

Render an interactive CLI menu where each option executes a shell command.

```
use PhpHelper\App;

App::cliMenu([
    'List files' => 'ls -al',
    'Run tests' => [
        'label' => 'Execute PHPUnit suite',
        'command' => 'vendor/bin/phpunit',
    ],
    'Migrate database' => './artisan migrate',
]);
```

- Only runs when invoked from the CLI; it exits early in web contexts.
- Accepts either `label => command` pairs or configuration arrays with a `command` key and optional `label`/`title`.
- Supports PHP callables via `run`/`callback`/`callable` entries for in-process actions.
- Displays the resulting exit code after each command, and supports quitting via `q`, `quit`, or `exit`.

---

Arrays
------

[](#arrays)

Comprehensive array manipulation utilities with dot notation support.

### Methods

[](#methods-2)

#### `get(array $array, string $key, mixed $default = null): mixed`

[](#getarray-array-string-key-mixed-default--null-mixed)

Get value using dot notation.

```
$data = [
    'user' => [
        'profile' => [
            'name' => 'John Doe',
            'email' => 'john@example.com'
        ]
    ]
];

$name = Arrays::get($data, 'user.profile.name');
echo $name; // "John Doe"

$phone = Arrays::get($data, 'user.profile.phone', 'Not provided');
echo $phone; // "Not provided"
```

#### `set(array &$array, string $key, mixed $value): void`

[](#setarray-array-string-key-mixed-value-void)

Set value using dot notation.

```
$data = [];
Arrays::set($data, 'config.database.host', 'localhost');
Arrays::set($data, 'config.database.port', 3306);
// Result: ['config' => ['database' => ['host' => 'localhost', 'port' => 3306]]]
```

#### `has(array $array, string $key): bool`

[](#hasarray-array-string-key-bool)

Check if key exists using dot notation.

```
$data = ['user' => ['name' => 'John']];
$exists = Arrays::has($data, 'user.name'); // true
$missing = Arrays::has($data, 'user.email'); // false
```

#### `forget(array &$array, string $key): void`

[](#forgetarray-array-string-key-void)

Remove value using dot notation.

```
$data = ['user' => ['name' => 'John', 'email' => 'john@example.com']];
Arrays::forget($data, 'user.email');
// Result: ['user' => ['name' => 'John']]
```

#### `flatten(array $array, int $depth = INF): array`

[](#flattenarray-array-int-depth--inf-array)

Flatten multi-dimensional array.

```
$nested = [1, [2, 3], [4, [5, 6]]];
$flat = Arrays::flatten($nested);
// Result: [1, 2, 3, 4, 5, 6]

$partialFlat = Arrays::flatten($nested, 1);
// Result: [1, 2, 3, 4, [5, 6]]
```

#### `dot(array $array, string $prepend = ''): array`

[](#dotarray-array-string-prepend---array)

Flatten array with dot notation keys.

```
$data = [
    'app' => [
        'name' => 'MyApp',
        'version' => '1.0'
    ]
];
$dotted = Arrays::dot($data);
// Result: ['app.name' => 'MyApp', 'app.version' => '1.0']
```

#### `only(array $array, array $keys): array`

[](#onlyarray-array-array-keys-array)

Get only specified keys.

```
$data = ['name' => 'John', 'email' => 'john@example.com', 'age' => 30];
$subset = Arrays::only($data, ['name', 'email']);
// Result: ['name' => 'John', 'email' => 'john@example.com']
```

#### `except(array $array, array $keys): array`

[](#exceptarray-array-array-keys-array)

Get all except specified keys.

```
$data = ['name' => 'John', 'email' => 'john@example.com', 'password' => 'secret'];
$safe = Arrays::except($data, ['password']);
// Result: ['name' => 'John', 'email' => 'john@example.com']
```

#### `first(array $array, ?callable $callback = null, mixed $default = null): mixed`

[](#firstarray-array-callable-callback--null-mixed-default--null-mixed)

Get first element matching criteria.

```
$numbers = [1, 2, 3, 4, 5];
$first = Arrays::first($numbers); // 1

$firstEven = Arrays::first($numbers, fn($n) => $n % 2 === 0); // 2
$firstLarge = Arrays::first($numbers, fn($n) => $n > 10, 'none'); // 'none'
```

#### `pluck(array $array, string $value, ?string $key = null): array`

[](#pluckarray-array-string-value-string-key--null-array)

Extract a column of values.

```
$users = [
    ['id' => 1, 'name' => 'John', 'email' => 'john@example.com'],
    ['id' => 2, 'name' => 'Jane', 'email' => 'jane@example.com']
];

$names = Arrays::pluck($users, 'name');
// Result: ['John', 'Jane']

$namesByEmail = Arrays::pluck($users, 'name', 'email');
// Result: ['john@example.com' => 'John', 'jane@example.com' => 'Jane']
```

#### `groupBy(array $array, string|callable $key): array`

[](#groupbyarray-array-stringcallable-key-array)

Group array by key or callback result.

```
$products = [
    ['name' => 'Laptop', 'category' => 'Electronics'],
    ['name' => 'Phone', 'category' => 'Electronics'],
    ['name' => 'Book', 'category' => 'Education']
];

$grouped = Arrays::groupBy($products, 'category');
// Result: [
//   'Electronics' => [['name' => 'Laptop', ...], ['name' => 'Phone', ...]],
//   'Education' => [['name' => 'Book', ...]]
// ]
```

#### `groupByValue(array $array): array`

[](#groupbyvaluearray-array-array)

Group array keys by their values (supports strings, ints, floats, etc.).

```
$labels = ['first' => 'red', 'second' => 'blue', 'third' => 'red', 'pi' => 3.14];
$grouped = Arrays::groupByValue($labels);
// Result: [
//   'red' => ['first', 'third'],
//   'blue' => ['second'],
//   '3.14' => ['pi']
// ]
```

#### `sortBy(array $array, string|callable $key, bool $descending = false): array`

[](#sortbyarray-array-stringcallable-key-bool-descending--false-array)

Sort array by key or callback.

```
$users = [
    ['name' => 'John', 'age' => 30],
    ['name' => 'Jane', 'age' => 25],
    ['name' => 'Bob', 'age' => 35]
];

$sorted = Arrays::sortBy($users, 'age');
// Sorted by age ascending

$sortedDesc = Arrays::sortBy($users, 'age', true);
// Sorted by age descending
```

#### `sumBy(array $array, string|callable|null $selector = null): float|int`

[](#sumbyarray-array-stringcallablenull-selector--null-floatint)

Sum numeric values, optionally using a key (with dot notation) or callback.

```
$orders = [
    ['price' => 12.5, 'quantity' => 2],
    ['price' => 7, 'quantity' => 1],
    ['price' => null, 'quantity' => 4],
];

$totalPrice = Arrays::sumBy($orders, 'price');
// Result: 19.5

$inventoryValue = Arrays::sumBy($orders, fn($order) => ($order['price'] ?? 0) * $order['quantity']);
// Result: 32.0

$plainSum = Arrays::sumBy([1, '2', 3.5]);
// Result: 6.5
```

#### `random(array $array, int $number = 1): mixed`

[](#randomarray-array-int-number--1-mixed)

Get random element(s).

```
$colors = ['red', 'green', 'blue', 'yellow'];
$randomColor = Arrays::random($colors); // e.g., 'green'
$randomColors = Arrays::random($colors, 2); // e.g., ['red', 'blue']
```

#### `keyBy(array $array, string|callable $key): array`

[](#keybyarray-array-stringcallable-key-array)

Key array by specific field value (supports dot notation).

```
$users = [
    ['id' => 1, 'name' => 'John', 'profile' => ['username' => 'john123']],
    ['id' => 2, 'name' => 'Jane', 'profile' => ['username' => 'jane456']]
];

$byId = Arrays::keyBy($users, 'id');
// Result: [1 => ['id' => 1, 'name' => 'John', ...], 2 => ['id' => 2, 'name' => 'Jane', ...]]

$byUsername = Arrays::keyBy($users, 'profile.username');
// Result: ['john123' => ['id' => 1, ...], 'jane456' => ['id' => 2, ...]]

// Using callback
$byFirstLetter = Arrays::keyBy($users, fn($user) => strtoupper($user['name'][0]));
// Result: ['J' => ['id' => 2, 'name' => 'Jane', ...]] (last John/Jane wins)
```

#### `last(array $array, ?callable $callback = null, mixed $default = null): mixed`

[](#lastarray-array-callable-callback--null-mixed-default--null-mixed)

Get last element matching criteria.

```
$numbers = [1, 2, 3, 4, 5];
$last = Arrays::last($numbers); // 5

$lastEven = Arrays::last($numbers, fn($n) => $n % 2 === 0); // 4
$lastLarge = Arrays::last($numbers, fn($n) => $n > 10, 'none'); // 'none'
```

#### `where(array $array, callable $callback): array`

[](#wherearray-array-callable-callback-array)

Filter array using callback.

```
$users = [
    ['name' => 'John', 'age' => 30, 'active' => true],
    ['name' => 'Jane', 'age' => 25, 'active' => false],
    ['name' => 'Bob', 'age' => 35, 'active' => true]
];

$adults = Arrays::where($users, fn($user) => $user['age'] >= 30);
// Result: [['name' => 'John', ...], ['name' => 'Bob', ...]]
```

#### `whereEquals(array $array, string $key, mixed $value): array`

[](#whereequalsarray-array-string-key-mixed-value-array)

Filter array where value equals.

```
$users = [
    ['name' => 'John', 'status' => 'active'],
    ['name' => 'Jane', 'status' => 'inactive'],
    ['name' => 'Bob', 'status' => 'active']
];

$activeUsers = Arrays::whereEquals($users, 'status', 'active');
// Result: [['name' => 'John', ...], ['name' => 'Bob', ...]]
```

#### `whereIn(array $array, string $key, array $values): array`

[](#whereinarray-array-string-key-array-values-array)

Filter array where value is in array.

```
$users = [
    ['name' => 'John', 'role' => 'admin'],
    ['name' => 'Jane', 'role' => 'user'],
    ['name' => 'Bob', 'role' => 'moderator']
];

$privilegedUsers = Arrays::whereIn($users, 'role', ['admin', 'moderator']);
// Result: [['name' => 'John', ...], ['name' => 'Bob', ...]]
```

#### `whereNotIn(array $array, string $key, array $values): array`

[](#wherenotinarray-array-string-key-array-values-array)

Filter array where value is not in array.

```
$users = [
    ['name' => 'John', 'role' => 'admin'],
    ['name' => 'Jane', 'role' => 'user'],
    ['name' => 'Bob', 'role' => 'banned']
];

$allowedUsers = Arrays::whereNotIn($users, 'role', ['banned', 'suspended']);
// Result: [['name' => 'John', ...], ['name' => 'Jane', ...]]
```

#### `isAssoc(array $array): bool`

[](#isassocarray-array-bool)

Check if array is associative.

```
$indexed = [1, 2, 3];
$assoc = ['name' => 'John', 'age' => 30];

echo Arrays::isAssoc($indexed); // false
echo Arrays::isAssoc($assoc); // true
```

#### `isSequential(array $array): bool`

[](#issequentialarray-array-bool)

Check if array is sequential (list).

```
$sequential = [1, 2, 3];
$assoc = ['name' => 'John', 'age' => 30];

echo Arrays::isSequential($sequential); // true
echo Arrays::isSequential($assoc); // false
```

#### `shuffle(array $array): array`

[](#shufflearray-array-array)

Shuffle array preserving keys.

```
$data = ['a' => 1, 'b' => 2, 'c' => 3];
$shuffled = Arrays::shuffle($data);
// Result: Keys preserved but order randomized, e.g., ['c' => 3, 'a' => 1, 'b' => 2]
```

#### `collapse(array $array): array`

[](#collapsearray-array-array)

Collapse array of arrays into single array.

```
$nested = [[1, 2], [3, 4], [5]];
$collapsed = Arrays::collapse($nested);
// Result: [1, 2, 3, 4, 5]
```

#### `crossJoin(array ...$arrays): array`

[](#crossjoinarray-arrays-array)

Cross join arrays.

```
$colors = ['red', 'blue'];
$sizes = ['S', 'M'];

$combinations = Arrays::crossJoin($colors, $sizes);
// Result: [['red', 'S'], ['red', 'M'], ['blue', 'S'], ['blue', 'M']]
```

#### `divide(array $array): array`

[](#dividearray-array-array)

Divide array into keys and values.

```
$data = ['name' => 'John', 'age' => 30];
[$keys, $values] = Arrays::divide($data);
// $keys = ['name', 'age']
// $values = ['John', 30]
```

#### `replaceRecursive(array $array, array ...$replacements): array`

[](#replacerecursivearray-array-array-replacements-array)

Recursively replace values in array.

```
$config = [
    'database' => ['host' => 'localhost', 'port' => 3306],
    'cache' => ['driver' => 'file']
];

$override = [
    'database' => ['host' => 'production.db.com'],
    'cache' => ['driver' => 'redis', 'ttl' => 3600]
];

$merged = Arrays::replaceRecursive($config, $override);
// Result: Nested arrays merged recursively
```

#### `duplicates(array $array): array`

[](#duplicatesarray-array-array)

Get duplicate values from array.

```
$items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
$dupes = Arrays::duplicates($items);
// Result: ['apple' => 3, 'banana' => 2]
```

#### `map(array $array, callable $callback): array`

[](#maparray-array-callable-callback-array)

Map array preserving keys.

```
$prices = ['apple' => 1.50, 'banana' => 0.75, 'orange' => 2.00];
$withTax = Arrays::map($prices, fn($price, $key) => $price * 1.1);
// Result: ['apple' => 1.65, 'banana' => 0.825, 'orange' => 2.2]
```

#### `mapRecursive(array $array, callable $callback): array`

[](#maprecursivearray-array-callable-callback-array)

Recursively map array.

```
$data = [
    'user' => ['name' => 'john', 'email' => 'JOHN@EXAMPLE.COM'],
    'meta' => ['tags' => ['PHP', 'javascript']]
];

$normalized = Arrays::mapRecursive($data, fn($value) => is_string($value) ? strtolower($value) : $value);
// Result: All string values converted to lowercase recursively
```

#### `wrap(mixed $value): array`

[](#wrapmixed-value-array)

Wrap value in array if not already an array.

```
$single = Arrays::wrap('hello'); // ['hello']
$multiple = Arrays::wrap(['a', 'b']); // ['a', 'b']
$null = Arrays::wrap(null); // []
```

#### `toQuery(string $array): string`

[](#toquerystring-array-string)

Convert array to query string.

```
$params = ['name' => 'John Doe', 'age' => 30, 'tags' => ['php', 'web']];
$query = Arrays::toQuery($params);
// Result: "name=John%20Doe&age=30&tags%5B0%5D=php&tags%5B1%5D=web"
```

#### `fromQuery(string $query): array`

[](#fromquerystring-query-array)

Parse query string to array.

```
$query = 'name=John%20Doe&age=30&active=1';
$params = Arrays::fromQuery($query);
// Result: ['name' => 'John Doe', 'age' => '30', 'active' => '1']
```

#### `chunk(array $array, int $size, bool $preserveKeys = false): array`

[](#chunkarray-array-int-size-bool-preservekeys--false-array)

Split array into chunks.

```
$numbers = [1, 2, 3, 4, 5, 6, 7];
$chunks = Arrays::chunk($numbers, 3);
// Result: [[1, 2, 3], [4, 5, 6], [7]]
```

---

AuthManager
-----------

[](#authmanager)

Complete user authentication and session management system.

### Configuration Options

[](#configuration-options-1)

```
AuthManager::init([
    'table' => 'users',                    // Users table name
    'email_column' => 'email',             // Email column name
    'password_column' => 'password',       // Password column name
    'primary_key' => 'id',                 // Primary key column
    'sessions' => true,                    // Enable session storage
    'session_key' => '_auth_user',         // Session key
    'remember_me' => true,                 // Enable remember me
    'remember_cookie' => 'phphelper_remember', // Cookie name
    'remember_duration' => 31104000,       // Cookie lifetime (360 days)
    'remember_secret' => 'your-secret',    // HMAC secret
    'remember_options' => [                // Cookie options
        'path' => '/',
        'domain' => null,
        'secure' => false,
        'httponly' => true,
        'samesite' => 'Lax'
    ]
]);
```

### Password Hashing

[](#password-hashing)

AuthManager hashes credentials with PHP's `password_hash()` using `PASSWORD_BCRYPT`. Existing hashes are transparently refreshed on login via `password_needs_rehash()` when configuration changes.

### Methods

[](#methods-3)

#### `init(array $config = []): void`

[](#initarray-config---void)

Initialize authentication manager.

```
// Basic setup
DB::sqlite(':memory:');
AuthManager::init();

// Custom configuration
AuthManager::init([
    'table' => 'members',
    'email_column' => 'username',
    'remember_duration' => 86400 * 7, // 7 days
    'remember_secret' => 'my-secret-key'
]);
```

#### `createUsersTable(array $options = []): void`

[](#createuserstablearray-options---void)

Create users table with appropriate schema.

```
// Create default table
AuthManager::createUsersTable();

// Custom table with extra columns
AuthManager::createUsersTable([
    'table' => 'members',
    'extra_columns' => [
        'first_name' => 'VARCHAR(100)',
        'last_name' => 'VARCHAR(100)',
        'is_active' => 'BOOLEAN DEFAULT TRUE'
    ]
]);
```

#### `register(string $email, string $password, array $attributes = []): array`

[](#registerstring-email-string-password-array-attributes---array)

Register new user.

```
// Basic registration
$user = AuthManager::register('john@example.com', 'password123');
echo $user['id']; // User ID

// With additional attributes
$user = AuthManager::register(
    'jane@example.com',
    'secure_password',
    [
        'first_name' => 'Jane',
        'last_name' => 'Doe',
        'role' => 'admin'
    ]
);
```

#### `login(string $email, string $password, bool $remember = false): ?array`

[](#loginstring-email-string-password-bool-remember--false-array)

Authenticate user.

```
// Basic login
$user = AuthManager::login('john@example.com', 'password123');
if ($user) {
    echo "Welcome, " . $user['email'];
} else {
    echo "Invalid credentials";
}

// With remember me
$user = AuthManager::login('john@example.com', 'password123', true);
```

#### `user(): ?array`

[](#user-array)

Get currently authenticated user.

```
$currentUser = AuthManager::user();
if ($currentUser) {
    echo "Logged in as: " . $currentUser['email'];
} else {
    echo "Not logged in";
}
```

#### `isLoggedIn(): bool`

[](#isloggedin-bool)

Check if user is authenticated.

```
if (AuthManager::isLoggedIn()) {
    // Show user dashboard
} else {
    // Redirect to login
}
```

#### `requireAuth(?callable $onUnauthenticated = null): array`

[](#requireauthcallable-onunauthenticated--null-array)

Ensure a user is authenticated.

```
$user = AuthManager::requireAuth();

// With custom unauthenticated handler
AuthManager::requireAuth(function () {
    Http::redirect('/login');
});
```

---

Config
------

[](#config)

Database-backed configuration management system.

### Configuration Options

[](#configuration-options-2)

```
Config::init([
    'table' => 'config',           // Configuration table name
    'key_column' => 'config_key',  // Key column name
    'value_column' => 'config_value' // Value column name
]);
```

### Methods

[](#methods-4)

#### `init(array $config = []): void`

[](#initarray-config---void-1)

Initialize configuration system.

```
DB::sqlite(':memory:');
Config::init();

// Custom table structure
Config::init([
    'table' => 'app_settings',
    'key_column' => 'setting_name',
    'value_column' => 'setting_value'
]);
```

#### `createConfigTable(array $options = []): void`

[](#createconfigtablearray-options---void)

Create configuration table.

```
Config::createConfigTable();
```

#### `set(string $key, ?string $value): void`

[](#setstring-key-string-value-void)

Set configuration value.

```
Config::set('app.name', 'My Application');
Config::set('app.version', '1.0.0');
Config::set('database.host', 'localhost');
```

#### `get(string $key, ?string $default = null): ?string`

[](#getstring-key-string-default--null-string)

Get configuration value.

```
$appName = Config::get('app.name', 'Default App');
$dbHost = Config::get('database.host');
$missing = Config::get('nonexistent.key', 'fallback');
```

#### `has(string $key): bool`

[](#hasstring-key-bool)

Check if configuration key exists.

```
if (Config::has('app.debug')) {
    $debug = Config::get('app.debug');
}
```

#### `delete(string $key): bool`

[](#deletestring-key-bool)

Remove configuration value.

```
$deleted = Config::delete('old.setting');
if ($deleted) {
    echo "Setting removed";
}
```

#### `all(): array`

[](#all-array)

Get all configuration values.

```
$allConfig = Config::all();
foreach ($allConfig as $key => $value) {
    echo "$key = $value\n";
}
```

---

Countries
---------

[](#countries)

Country data with flags, ISO codes, and names.

### Methods

[](#methods-5)

#### `getAll(): array`

[](#getall-array)

Get all countries array.

```
$countries = Countries::getAll();
```

#### `getByCode(string $code): ?array`

[](#getbycodestring-code-array)

Get country by ISO/ISO3 code.

```
$country = Countries::getByCode('US'); // ["flag" => "🇺🇸", "name" => "United States"]
$country = Countries::getByCode('USA'); // Same result
$country = Countries::getByCode('DE'); // ["flag" => "🇩🇪", "name" => "Germany"]
```

#### `getByName(string $name): ?array`

[](#getbynamestring-name-array)

Get country by name.

```
$country = Countries::getByName('France'); // ["flag" => "🇫🇷", "name" => "France"]
```

#### `nameWithFlag(string $code): ?string`

[](#namewithflagstring-code-string)

Get formatted name with flag.

```
echo Countries::nameWithFlag('JP'); // "🇯🇵 Japan"
echo Countries::nameWithFlag('BRA'); // "🇧🇷 Brazil"
```

### Usage Examples

[](#usage-examples)

```
// Country dropdown
$countries = Countries::getAll();
foreach ($countries as $code => $data) {
    if (strlen($code) === 2) { // ISO codes only
        echo "{$data['flag']} {$data['name']}";
    }
}

// Validate country code
if (Countries::getByCode($_POST['country'])) {
    // Valid country
}

// Display user country
$userCountry = Countries::nameWithFlag($user['country_code']);
echo "From: {$userCountry}";
```

---

DB
--

[](#db)

Database abstraction layer providing clean PDO interface.

### Configuration Options

[](#configuration-options-3)

```
// MySQL connection options
DB::mysql('database_name', 'username', 'password', [
    'host' => '127.0.0.1',        // Database host
    'port' => 3306,               // Port number
    'charset' => 'utf8mb4',       // Character set
    'unix_socket' => null,        // Unix socket path
    'attributes' => [             // PDO attributes
        PDO::ATTR_TIMEOUT => 30
    ]
]);

// PostgreSQL connection options
DB::pgsql('database_name', 'username', 'password', [
    'host' => '127.0.0.1',
    'port' => 5432,
    'sslmode' => 'prefer',        // SSL mode
    'charset' => 'utf8',
    'application_name' => 'MyApp',
    'attributes' => []
]);

// SQLite connection options
DB::sqlite('/path/to/database.db', null, null, [
    'memory' => false,            // Use in-memory database
    'attributes' => []
]);
```

### Methods

[](#methods-6)

#### `connect(string $dsn, ?string $username = null, ?string $password = null, array $options = []): void`

[](#connectstring-dsn-string-username--null-string-password--null-array-options---void)

Establish PDO connection.

```
// Manual DSN
DB::connect('mysql:host=localhost;dbname=test', 'user', 'pass');
```

#### `mysql(string $dbname, ?string $username = null, ?string $password = null, array $options = []): void`

[](#mysqlstring-dbname-string-username--null-string-password--null-array-options---void)

Connect to MySQL/MariaDB.

```
// Basic connection
DB::mysql('myapp', 'root', 'password');

// With custom host and port
DB::mysql('myapp', 'user', 'pass', [
    'host' => 'db.example.com',
    'port' => 3307,
    'charset' => 'utf8mb4'
]);

// Unix socket connection
DB::mysql('myapp', 'user', 'pass', [
    'unix_socket' => '/var/run/mysqld/mysqld.sock'
]);
```

#### `pgsql(string $dbname, ?string $username = null, ?string $password = null, array $options = []): void`

[](#pgsqlstring-dbname-string-username--null-string-password--null-array-options---void)

Connect to PostgreSQL.

```
DB::pgsql('myapp', 'postgres', 'password', [
    'host' => 'localhost',
    'port' => 5432,
    'sslmode' => 'require'
]);
```

#### `sqlite(string $pathOrDsn = ':memory:', ?string $username = null, ?string $password = null, array $options = []): void`

[](#sqlitestring-pathordsn--memory-string-username--null-string-password--null-array-options---void)

Connect to SQLite.

```
// File database
DB::sqlite('/path/to/database.db');

// In-memory database
DB::sqlite(':memory:');
// or
DB::sqlite('', null, null, ['memory' => true]);
```

#### `query(string $sql, array $params = []): PDOStatement`

[](#querystring-sql-array-params---pdostatement)

Execute query and return statement.

```
$stmt = DB::query('SELECT * FROM users WHERE age > ?', [18]);
while ($row = $stmt->fetch()) {
    echo $row['name'] . "\n";
}
```

#### `getRow(string $sql, array $params = []): ?array`

[](#getrowstring-sql-array-params---array)

Get single row.

```
$user = DB::getRow('SELECT * FROM users WHERE id = ?', [123]);
if ($user) {
    echo $user['name'];
}
```

#### `getRows(string $sql, array $params = []): array`

[](#getrowsstring-sql-array-params---array)

Get all matching rows.

```
$users = DB::getRows('SELECT * FROM users WHERE active = ?', [1]);
foreach ($users as $user) {
    echo $user['name'] . "\n";
}
```

#### `getValue(string $sql, array $params = []): mixed`

[](#getvaluestring-sql-array-params---mixed)

Get single scalar value.

```
$count = DB::getValue('SELECT COUNT(*) FROM users');
$name = DB::getValue('SELECT name FROM users WHERE id = ?', [123]);
```

#### `insert(string $table, array $data): string`

[](#insertstring-table-array-data-string)

Insert row and return ID.

```
$id = DB::insert('users', [
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'created_at' => date('Y-m-d H:i:s')
]);
echo "Created user with ID: $id";
```

#### `update(string $table, array $data, string $where, array $params = []): int`

[](#updatestring-table-array-data-string-where-array-params---int)

Update rows.

```
$affected = DB::update(
    'users',
    ['last_login' => date('Y-m-d H:i:s')],
    'id = ?',
    [123]
);
echo "Updated $affected rows";
```

#### `upsert(string $table, array $data, array|string $conflictColumns, ?array $updateColumns = null): void`

[](#upsertstring-table-array-data-arraystring-conflictcolumns-array-updatecolumns--null-void)

Insert or update on conflict.

```
// Insert or update user by email
DB::upsert(
    'users',
    ['email' => 'john@example.com', 'name' => 'John Doe', 'login_count' => 1],
    'email', // conflict column
    ['name', 'login_count'] // columns to update
);
```

#### `delete(string $table, string $where, array $params = []): int`

[](#deletestring-table-string-where-array-params---int)

Delete rows.

```
$deleted = DB::delete('users', 'active = ?', [0]);
echo "Deleted $deleted inactive users";
```

#### `transaction(callable $callback): mixed`

[](#transactioncallable-callback-mixed)

Execute in transaction.

```
$result = DB::transaction(function() {
    $userId = DB::insert('users', ['name' => 'John']);
    DB::insert('profiles', ['user_id' => $userId, 'bio' => 'Developer']);
    return $userId;
});
```

#### `cliBackupRestoreOptions(string $dbname, string $dbUser, string $dbPassword, array $options = []): array`

[](#clibackuprestoreoptionsstring-dbname-string-dbuser-string-dbpassword-array-options---array)

Generate menu-ready callbacks for backing up or restoring a MySQL database from the CLI.

```
use PhpHelper\{App, DB};

if (App::isCli()) {
    $menu = DB::cliBackupRestoreOptions('phphelper', 'root', 'secret', [
        'defaults' => [
            'file' => 'storage/backups/local.sql',
        ],
        'backup_options' => [
            'mysqldump_path' => '/usr/local/mysql/bin/mysqldump',
        ],
    ]);

    App::cliMenu($menu);
}
```

- Returns an array compatible with `App::cliMenu`, combining either or both "Backup" and "Restore" actions.
- Respects `defaults`, `backup_options`, `restore_options`, and optional `mode` (`backup` or `restore`) to limit which entries are generated.
- Each callback prints progress messages and delegates to `DB::backup()` / `DB::restore()` internally.

---

Date
----

[](#date)

Date and time formatting utilities with human-friendly output.

### Methods

[](#methods-7)

#### `ago(\DateTimeInterface|int|string $timestamp, bool $full = false): string`

[](#agodatetimeinterfaceintstring-timestamp-bool-full--false-string)

Get human-readable relative time.

```
// Recent time
echo Date::ago(time() - 3600); // "1 hour ago"
echo Date::ago('2023-01-01 12:00:00'); // "5 months ago"

// Full format
echo Date::ago(time() - 3665, true); // "1 hour, 1 minute, 5 seconds ago"

// Future time
echo Date::ago(time() + 1800); // "30 minutes from now"
```

#### `format(\DateTimeInterface|int|string $timestamp, string $format = 'datetime', ?string $timezone = null): string`

[](#formatdatetimeinterfaceintstring-timestamp-string-format--datetime-string-timezone--null-string)

Format dates with presets or custom patterns.

**Available Presets:**

- `date` → Y-m-d
- `datetime` → Y-m-d H:i
- `datetime_seconds` → Y-m-d H:i:s
- `time` → H:i
- `time_seconds` → H:i:s
- `iso` → ISO 8601 format
- `rfc2822` → RFC 2822 format
- `rss` → RSS format
- `human` → j M Y
- `human_full` → j F Y, H:i

```
$now = time();

// Preset formats
echo Date::format($now, 'date'); // "2023-12-25"
echo Date::format($now, 'datetime'); // "2023-12-25 14:30"
echo Date::format($now, 'human'); // "25 Dec 2023"
echo Date::format($now, 'iso'); // "2023-12-25T14:30:00+00:00"

// Custom format
echo Date::format($now, 'l, F j, Y'); // "Monday, December 25, 2023"

// With timezone
echo Date::format($now, 'datetime', 'America/New_York');
echo Date::format('2023-12-25 10:00:00 UTC', 'datetime', 'Asia/Tokyo');
```

#### `timestamp(\DateTimeInterface|int|string|null $value = null, ?string $timezone = null): int`

[](#timestampdatetimeinterfaceintstringnull-value--null-string-timezone--null-int)

Get UNIX timestamp.

```
// Current timestamp
$now = Date::timestamp(); // equivalent to time()

// From various inputs
$ts1 = Date::timestamp('2023-12-25 12:00:00');
$ts2 = Date::timestamp(new DateTime('2023-12-25'));
$ts3 = Date::timestamp('Dec 25, 2023', 'America/New_York');
```

---

Files
-----

[](#files)

File system operations and utilities.

### Methods

[](#methods-8)

#### `read(string $path): string|false`

[](#readstring-path-stringfalse)

Read file contents.

```
$content = Files::read('/path/to/file.txt');
if ($content !== false) {
    echo $content;
} else {
    echo "File not found or not readable";
}
```

#### `write(string $path, string $content, int $flags = 0): int|false`

[](#writestring-path-string-content-int-flags--0-intfalse)

Write content to file.

```
// Basic write
$bytes = Files::write('/path/to/file.txt', 'Hello World');

// Append to file
$bytes = Files::write('/path/to/file.txt', 'More content', FILE_APPEND);

// Write with lock
$bytes = Files::write('/path/to/file.txt', 'Safe content', LOCK_EX);
```

#### `append(string $path, string $content): int|false`

[](#appendstring-path-string-content-intfalse)

Append content to file.

```
Files::append('/path/to/log.txt', date('Y-m-d H:i:s') . " - Log entry\n");
```

#### `copy(string $source, string $dest): bool`

[](#copystring-source-string-dest-bool)

Copy file.

```
$success = Files::copy('/source/file.txt', '/destination/file.txt');
```

#### `move(string $source, string $dest): bool`

[](#movestring-source-string-dest-bool)

Move/rename file.

```
$success = Files::move('/old/path.txt', '/new/path.txt');
```

#### `download(string $url, string $savePath): bool`

[](#downloadstring-url-string-savepath-bool)

Download a file from a URL to a local path.

```
$ok = Files::download('https://example.com/file.zip', '/path/to/file.zip');
if (!$ok) {
    echo "Download failed";
}
```

#### `delete(string $path): bool`

[](#deletestring-path-bool)

Delete file.

```
$deleted = Files::delete('/path/to/unwanted.txt');
```

#### `exists(string $path): bool`

[](#existsstring-path-bool)

Check if file exists.

```
if (Files::exists('/path/to/file.txt')) {
    echo "File exists";
}
```

#### `size(string $path): int|false`

[](#sizestring-path-intfalse)

Get file size in bytes.

```
$size = Files::size('/path/to/file.txt');
echo "File size: " . Format::bytes($size);
```

#### `extension(string $path): string`

[](#extensionstring-path-string)

Get file extension.

```
$ext = Files::extension('/path/to/document.pdf'); // "pdf"
$ext = Files::extension('image.JPEG'); // "jpeg"
```

#### `mimeType(string $path): string|false`

[](#mimetypestring-path-stringfalse)

Get MIME type.

```
$mime = Files::mimeType('/path/to/image.jpg'); // "image/jpeg"
```

#### `readJson(string $path): mixed`

[](#readjsonstring-path-mixed)

Read and parse JSON file.

```
$data = Files::readJson('/path/to/config.json');
if ($data !== false) {
    echo $data['app']['name'];
}
```

#### `writeJson(string $path, mixed $data, int $flags = JSON_PRETTY_PRINT): int|false`

[](#writejsonstring-path-mixed-data-int-flags--json_pretty_print-intfalse)

Write data as JSON.

```
$config = ['app' => ['name' => 'MyApp', 'version' => '1.0']];
Files::writeJson('/path/to/config.json', $config);

// Compact JSON
Files::writeJson('/path/to/data.json', $data, 0);
```

#### `readCsv(string $path, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): array|false`

[](#readcsvstring-path-string-delimiter---string-enclosure---string-escape---arrayfalse)

Read CSV file.

```
$rows = Files::readCsv('/path/to/data.csv');
foreach ($rows as $row) {
    echo implode(' | ', $row) . "\n";
}

// Custom delimiter
$rows = Files::readCsv('/path/to/data.tsv', "\t");
```

#### `writeCsv(string $path, array $data, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): bool`

[](#writecsvstring-path-array-data-string-delimiter---string-enclosure---string-escape---bool)

Write CSV file.

```
$data = [
    ['Name', 'Email', 'Age'],
    ['John Doe', 'john@example.com', '30'],
    ['Jane Smith', 'jane@example.com', '25']
];
Files::writeCsv('/path/to/export.csv', $data);
```

#### `hash(string $path, string $algo = 'sha256'): string|false`

[](#hashstring-path-string-algo--sha256-stringfalse)

Get file hash.

```
$sha256 = Files::hash('/path/to/file.txt');
$md5 = Files::hash('/path/to/file.txt', 'md5');
```

#### `createDirectory(string $path, int $permissions = 0755): bool`

[](#createdirectorystring-path-int-permissions--0755-bool)

Create directory recursively.

```
Files::createDirectory('/path/to/nested/directory');
```

#### `deleteDirectory(string $path): bool`

[](#deletedirectorystring-path-bool)

Delete directory recursively.

```
Files::deleteDirectory('/path/to/temp/folder');
```

#### `listFiles(string $path, string $pattern = '*'): array`

[](#listfilesstring-path-string-pattern---array)

List files in directory.

```
$allFiles = Files::listFiles('/path/to/directory');
$phpFiles = Files::listFiles('/path/to/src', '*.php');
$images = Files::listFiles('/uploads', '*.{jpg,png,gif}');
```

---

Format
------

[](#format)

Data formatting utilities for human-readable output.

### Methods

[](#methods-9)

#### `bytes(int $bytes, int $precision = 2, string $system = 'binary', ?array $units = null): string`

[](#bytesint-bytes-int-precision--2-string-system--binary-array-units--null-string)

Format bytes into human-readable sizes.

**System Options:**

- `binary` (default): 1024-based with KB/MB/GB
- `iec`: 1024-based with KiB/MiB/GiB
- `si`: 1000-based with KB/MB/GB

```
echo Format::bytes(1536); // "1.50 KB"
echo Format::bytes(1048576); // "1.00 MB"
echo Format::bytes(1536, 1, 'iec'); // "1.5 KiB"
echo Format::bytes(1000, 2, 'si'); // "1.00 KB"

// Custom units
echo Format::bytes(1024, 2, 'binary', ['B', 'Kilobytes', 'Megabytes']);
```

#### `number(float|int $value, int $decimals = 0, string $decimalPoint = '.', string $thousandsSep = ','): string`

[](#numberfloatint-value-int-decimals--0-string-decimalpoint---string-thousandssep---string)

Format numbers.

```
echo Format::number(1234.567); // "1,235"
echo Format::number(1234.567, 2); // "1,234.57"
echo Format::number(1234.567, 2, ',', ' '); // "1 234,57"
```

#### `currency(float $amount, string $currency = 'USD', ?string $locale = null, ?int $precision = null): string`

[](#currencyfloat-amount-string-currency--usd-string-locale--null-int-precision--null-string)

Format currency amounts.

```
echo Format::currency(1234.56); // "1,234.56 USD"
echo Format::currency(1234.56, 'EUR', 'de_DE'); // "1.234,56 €"
echo Format::currency(1234.56, 'USD', 'en_US'); // "$1,234.56"
echo Format::currency(1234.5, 'USD', null, 0); // "$1,235"
```

#### `percent(float $value, int $precision = 0, bool $fromFraction = true): string`

[](#percentfloat-value-int-precision--0-bool-fromfraction--true-string)

Format percentages.

```
echo Format::percent(0.1234); // "12%"
echo Format::percent(0.1234, 2); // "12.34%"
echo Format::percent(12.34, 1, false); // "12.3%" (already percentage)
```

#### `shortNumber(float|int $value, int $precision = 1): string`

[](#shortnumberfloatint-value-int-precision--1-string)

Format large numbers with abbreviations.

```
echo Format::shortNumber(1234); // "1.2K"
echo Format::shortNumber(1234567); // "1.2M"
echo Format::shortNumber(1234567890); // "1.2B"
echo Format::shortNumber(1500, 0); // "2K"
```

#### `duration(int $seconds, bool $compact = true): string`

[](#durationint-seconds-bool-compact--true-string)

Format time duration.

```
echo Format::duration(3665); // "1h 1m 5s"
echo Format::duration(3665, false); // "1 hour, 1 minute, 5 seconds"
echo Format::duration(90); // "1m 30s"
echo Format::duration(86400); // "1d"
```

#### `hms(int $seconds, bool $withDays = false): string`

[](#hmsint-seconds-bool-withdays--false-string)

Format as HH:MM:SS clock time.

```
echo Format::hms(3665); // "01:01:05"
echo Format::hms(90065, true); // "1d 01:01:05"
```

#### `ordinal(int $number): string`

[](#ordinalint-number-string)

Add ordinal suffix to numbers.

```
echo Format::ordinal(1); // "1st"
echo Format::ordinal(22); // "22nd"
echo Format::ordinal(103); // "103rd"
echo Format::ordinal(11); // "11th"
```

#### `parseBytes(string $size): int`

[](#parsebytesstring-size-int)

Parse human-readable size to bytes.

```
echo Format::parseBytes('1.5K'); // 1536
echo Format::parseBytes('2M'); // 2097152
echo Format::parseBytes('1.5 GB'); // 1610612736
echo Format::parseBytes('500'); // 500
```

#### `bool(mixed $value, string $true = 'Yes', string $false = 'No', string $null = ''): string`

[](#boolmixed-value-string-true--yes-string-false--no-string-null---string)

Format boolean values.

```
echo Format::bool(true); // "Yes"
echo Format::bool(false); // "No"
echo Format::bool(1); // "Yes"
echo Format::bool('true'); // "Yes"
echo Format::bool(null); // ""
echo Format::bool(true, 'Active', 'Inactive'); // "Active"
```

#### `json(mixed $value, bool $pretty = true, int $flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES): string`

[](#jsonmixed-value-bool-pretty--true-int-flags--json_unescaped_unicode--json_unescaped_slashes-string)

Format JSON for display.

```
$data = ['name' => 'John', 'age' => 30];
echo Format::json($data); // Pretty printed JSON
echo Format::json($data, false); // Compact JSON
```

---

Http
----

[](#http)

HTTP utilities and client information detection.

### Methods

[](#methods-10)

#### `redirect(string $url, int $statusCode = 302, bool $exit = true): void`

[](#redirectstring-url-int-statuscode--302-bool-exit--true-void)

Redirect to URL.

```
// Simple redirect
Http::redirect('/dashboard');

// Permanent redirect
Http::redirect('https://example.com', 301);

// Don't exit after redirect
Http::redirect('/page', 302, false);
```

#### `download(string $filename, string $mimetype = 'application/octet-stream')`

[](#downloadstring-filename-string-mimetype--applicationoctet-stream)

Stream file as download.

```
// Download file
Http::download('/path/to/document.pdf', 'application/pdf');

// Let browser detect MIME type
Http::download('/path/to/image.jpg');
```

#### `json(mixed $data, int $status = 200, array $headers = []): void`

[](#jsonmixed-data-int-status--200-array-headers---void)

Output JSON response.

```
// Simple JSON response
Http::json(['status' => 'success', 'data' => $result]);

// With custom status and headers
Http::json(
    ['error' => 'Not found'],
    404,
    ['X-Custom-Header' => 'value']
);
```

#### `clientInfo(): array`

[](#clientinfo-array)

Get comprehensive client information.

```
$info = Http::clientInfo();

// IP information
echo $info['ip']; // Primary IP address
print_r($info['ips']); // All detected IPs
echo $info['is_proxy'] ? 'Behind proxy' : 'Direct';

// Browser detection
echo $info['browser']; // "Chrome", "Firefox", etc.
echo $info['browser_version']; // "91.0.4472.124"
echo $info['os']; // "Windows", "macOS", "Linux", etc.
echo $info['engine']; // "Blink", "Gecko", "WebKit"

// Device classification
echo $info['device']; // "desktop", "mobile", "tablet", "bot"
echo $info['is_mobile'] ? 'Mobile' : 'Not mobile';
echo $info['is_tablet'] ? 'Tablet' : 'Not tablet';
echo $info['is_bot'] ? 'Bot detected' : 'Human user';

// Language preferences
echo $info['accept_language']; // Raw header
print_r($info['languages']); // Parsed languages by preference

// Request information
echo $info['method']; // "GET", "POST", etc.
echo $info['scheme']; // "http" or "https"
echo $info['host']; // "example.com"
echo $info['port']; // 80, 443, etc.
echo $info['path']; // "/path/to/page"
echo $info['query']; // "param=value"
echo $info['url']; // Full URL
echo $info['referer']; // Referring page
```

---

Logs
----

[](#logs)

Database-backed logging system with multiple severity levels.

### Configuration Options

[](#configuration-options-4)

```
Logs::init([
    'table' => 'logs',                    // Log table name
    'context_defaults' => [               // Data merged into every context payload
        'application' => 'MyApp',
        'environment' => 'production',
        'user_id' => getCurrentUserId(),
    ],
    'meta_defaults' => [                  // Data merged into every meta payload
        'request_id' => $_SERVER['HTTP_X_REQUEST_ID'] ?? null,
        'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
    ],
]);
```

### Methods

[](#methods-11)

#### `init(array $config = []): void`

[](#initarray-config---void-2)

Initialize logging system.

```
DB::sqlite(':memory:');
Logs::init([
    'table' => 'application_logs',
    'context_defaults' => [
        'app_version' => '1.0.0',
        'server' => $_SERVER['SERVER_NAME'] ?? 'unknown',
    ],
    'meta_defaults' => [
        'environment' => getenv('APP_ENV') ?: 'local',
    ],
]);
```

#### `createLogsTable(?string $table = null): void`

[](#createlogstablestring-table--null-void)

Create logs table.

```
Logs::createLogsTable(); // Use configured table
Logs::createLogsTable('custom_logs'); // Custom table name
```

#### `log(string $level, string $message, array $context = [], array $meta = []): string`

[](#logstring-level-string-message-array-context---array-meta---string)

Log message with custom level.

```
$id = Logs::log('custom', 'User action performed', [
    'user_id' => 123,
    'action' => 'file_upload',
    'file_name' => 'document.pdf'
], [
    'ip_address' => $_SERVER['REMOTE_ADDR'],
    'user_agent' => $_SERVER['HTTP_USER_AGENT']
]);
```

#### Log Level Methods

[](#log-level-methods)

Pre-defined methods for standard log levels:

```
// Debug information
Logs::debug('Query executed', ['sql' => 'SELECT * FROM users', 'time' => 0.023]);

// General information
Logs::info('User logged in', ['user_id' => 123, 'email' => 'john@example.com']);

// Success operations
Logs::success('File uploaded successfully', ['filename' => 'document.pdf', 'size' => 1024]);

// Notices
Logs::notice('Configuration changed', ['setting' => 'debug_mode', 'old' => false, 'new' => true]);

// Warnings
Logs::warning('Low disk space', ['disk' => '/var', 'available' => '500MB']);

// Errors
Logs::error('Database connection failed', ['host' => 'localhost', 'error' => 'Connection refused']);

// Critical issues
Logs::critical('Payment processing failed', ['transaction_id' => 'tx_123', 'amount' => 99.99]);

// Alerts requiring immediate attention
Logs::alert('Security breach detected', ['ip' => '192.168.1.100', 'attempts' => 50]);

// Emergency situations
Logs::emergency('System shutdown imminent', ['reason' => 'memory_exhausted']);
```

#### `setContextDefaults(array $defaults): void`

[](#setcontextdefaultsarray-defaults-void)

Merge values into every context payload.

```
Logs::setContextDefaults([
    'user_id' => getCurrentUserId(),
    'session_id' => session_id(),
]);
```

#### `setMetaDefaults(array $defaults): void`

[](#setmetadefaultsarray-defaults-void)

Merge values into every meta payload.

```
Logs::setMetaDefaults([
    'request_id' => uniqid(),
    'server' => $_SERVER['SERVER_NAME'] ?? 'unknown',
]);
```

---

PrettyErrorHandler
------------------

[](#prettyerrorhandler)

Enhanced error display for development and debugging.

### Configuration Options

[](#configuration-options-5)

```
PrettyErrorHandler::init([
    'display' => true,              // Force display errors
    'report' => E_ALL,              // Error reporting level
    'context_before' => 6,          // Lines before error
    'context_after' => 4,           // Lines after error
    'show_trace' => true,           // Include backtrace
    'overlay' => true,              // Render as overlay vs full page
    'skip_warnings' => false,       // Skip PHP warnings
    'log_errors' => false          // Log to pretty_errors.txt
]);
```

### Methods

[](#methods-12)

#### `init(array $options = []): self`

[](#initarray-options---self)

Enable pretty error handling.

```
// Basic setup for development
PrettyErrorHandler::init();

// Custom configuration
PrettyErrorHandler::init([
    'overlay' => false,        // Full page instead of overlay
    'context_before' => 10,    // More context lines
    'log_errors' => true,      // Save errors to file
    'skip_warnings' => true    // Only show errors and fatals
]);
```

#### `__construct(array $options = [], bool $registerGlobal = true)`

[](#__constructarray-options---bool-registerglobal--true)

Create handler instance.

```
// Auto-register
$handler = new PrettyErrorHandler([
    'show_trace' => false,
    'overlay' => true
]);

// Manual registration
$handler = new PrettyErrorHandler(['display' => true], false);
$handler->register();
```

### Features

[](#features)

- **Syntax-highlighted code context** around error line
- **Clean stack traces** with clickable file paths
- **Overlay mode** that doesn't disrupt page layout
- **Copy-to-clipboard** functionality for error details
- **CLI support** with colored output
- **Error logging** to file for production debugging

---

Str
---

[](#str)

Comprehensive string manipulation utilities.

### Methods

[](#methods-13)

#### `startsWith(string $text, string|array $prefixes, bool $caseSensitive = true): bool`

[](#startswithstring-text-stringarray-prefixes-bool-casesensitive--true-bool)

Check if string starts with prefix(es).

```
$url = 'https://example.com';
echo Str::startsWith($url, 'https://'); // true
echo Str::startsWith($url, ['http://', 'https://']); // true
echo Str::startsWith('Hello', 'HELLO', false); // true (case insensitive)
```

#### `endsWith(string $text, string|array $suffixes, bool $caseSensitive = true): bool`

[](#endswithstring-text-stringarray-suffixes-bool-casesensitive--true-bool)

Check if string ends with suffix(es).

```
$filename = 'document.PDF';
echo Str::endsWith($filename, '.pdf', false); // true
echo Str::endsWith($filename, ['.doc', '.pdf'], false); // true
```

#### `contains(string $text, string|array $fragments, bool $caseSensitive = true): bool`

[](#containsstring-text-stringarray-fragments-bool-casesensitive--true-bool)

Check if string contains fragment(s).

```
$text = 'The quick brown fox';
echo Str::contains($text, 'quick'); // true
echo Str::contains($text, ['cat', 'fox']); // true
echo Str::contains($text, 'QUICK', false); // true
```

#### `slug(string $value, string $separator = '-'): string`

[](#slugstring-value-string-separator----string)

Convert to URL-friendly slug.

```
echo Str::slug('Hello World!'); // "hello-world"
echo Str::slug('Café & Restaurant', '_'); // "cafe_restaurant"
echo Str::slug('Ñoño García'); // "nono-garcia"
```

#### `camel(string $value): string`

[](#camelstring-value-string)

Convert to camelCase.

```
echo Str::camel('hello_world'); // "helloWorld"
echo Str::camel('user-name'); // "userName"
echo Str::camel('first name'); // "firstName"
```

#### `snake(string $value, string $delimiter = '_'): string`

[](#snakestring-value-string-delimiter--_-string)

Convert to snake\_case.

```
echo Str::snake('HelloWorld'); // "hello_world"
echo Str::snake('userName'); // "user_name"
echo Str::snake('XMLParser', '-'); // "xml-parser"
```

#### `studly(string $value): string`

[](#studlystring-value-string)

Convert to StudlyCase.

```
echo Str::studly('hello_world'); // "HelloWorld"
echo Str::studly('user-name'); // "UserName"
```

#### `upper(string $value, ?string $lang = null): string`

[](#upperstring-value-string-lang--null-string)

Convert to uppercase with locale support.

```
echo Str::upper('hello world'); // "HELLO WORLD"
echo Str::upper('café', 'tr'); // Turkish locale
```

#### `lower(string $value, ?string $lang = null): string`

[](#lowerstring-value-string-lang--null-string)

Convert to lowercase with locale support.

```
echo Str::lower('HELLO WORLD'); // "hello world"
echo Str::lower('CAFÉ', 'tr'); // Turkish locale
```

#### `title(string $value, ?string $lang = null): string`

[](#titlestring-value-string-lang--null-string)

Convert to Title Case.

```
echo Str::title('hello world'); // "Hello World"
echo Str::title('HELLO WORLD'); // "Hello World"
```

#### `limit(string $value, int $limit = 100, string $end = '...'): string`

[](#limitstring-value-int-limit--100-string-end---string)

Limit string length.

```
$text = 'This is a very long string that needs to be truncated';
echo Str::limit($text, 20); // "This is a very long..."
echo Str::limit($text, 20, ' [more]'); // "This is a very long [more]"
```

#### `words(string $value, int $words = 100, string $end = '...'): string`

[](#wordsstring-value-int-words--100-string-end---string)

Limit word count.

```
$text = 'Lorem ipsum dolor sit amet consectetur adipiscing elit';
echo Str::words($text, 4); // "Lorem ipsum dolor sit..."
echo Str::words($text, 3, ' [continue]'); // "Lorem ipsum dolor [continue]"
```

#### `before(string $text, string $search, bool $caseSensitive = true): string`

[](#beforestring-text-string-search-bool-casesensitive--true-string)

Get text before first occurrence.

```
echo Str::before('user@example.com', '@'); // "user"
echo Str::before('Hello World', ' '); // "Hello"
```

#### `after(string $text, string $search, bool $caseSensitive = true): string`

[](#afterstring-text-string-search-bool-casesensitive--true-string)

Get text after first occurrence.

```
echo Str::after('user@example.com', '@'); // "example.com"
echo Str::after('Hello World', ' '); // "World"
```

#### `between(string $text, string $from, string $to, bool $caseSensitive = true): ?string`

[](#betweenstring-text-string-from-string-to-bool-casesensitive--true-string)

Extract text between delimiters.

```
echo Str::between('Hello [World] Test', '[', ']'); // "World"
echo Str::between('Title', '', ''); // "Title"
echo Str::between('No match here', '[', ']'); // null
```

#### `replaceFirst(string $text, string $search, string $replace, bool $caseSensitive = true): string`

[](#replacefirststring-text-string-search-string-replace-bool-casesensitive--true-string)

Replace first occurrence.

```
echo Str::replaceFirst('foo bar foo', 'foo', 'baz'); // "baz bar foo"
```

#### `replaceLast(string $text, string $search, string $replace, bool $caseSensitive = true): string`

[](#replacelaststring-text-string-search-string-replace-bool-casesensitive--true-string)

Replace last occurrence.

```
echo Str::replaceLast('foo bar foo', 'foo', 'baz'); // "foo bar baz"
```

#### `ensurePrefix(string $text, string $prefix, bool $caseSensitive = true): string`

[](#ensureprefixstring-text-string-prefix-bool-casesensitive--true-string)

Ensure string starts with prefix.

```
echo Str::ensurePrefix('example.com', 'https://'); // "https://example.com"
echo Str::ensurePrefix('https://example.com', 'https://'); // "https://example.com"
```

#### `ensureSuffix(string $text, string $suffix, bool $caseSensitive = true): string`

[](#ensuresuffixstring-text-string-suffix-bool-casesensitive--true-string)

Ensure string ends with suffix.

```
echo Str::ensureSuffix('filename', '.txt'); // "filename.txt"
echo Str::ensureSuffix('filename.txt', '.txt'); // "filename.txt"
```

#### `squish(string $text): string`

[](#squishstring-text-string)

Collapse whitespace and trim.

```
echo Str::squish("  Hello\n\t World  "); // "Hello World"
```

#### `randomString(int $length = 16): string`

[](#randomstringint-length--16-string)

Generate cryptographically secure random string.

```
echo Str::randomString(); // e.g., "aB3xY9mK2nP7qR8s"
echo Str::randomString(32); // 32-character string
```

#### `uuid4(): string`

[](#uuid4-string)

Generate UUID v4.

```
echo Str::uuid4(); // e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479"
```

#### `isJson(string $value): bool`

[](#isjsonstring-value-bool)

Check if string is valid JSON.

```
echo Str::isJson('{"name":"John"}'); // true
echo Str::isJson('invalid json'); // false
```

#### SEO and Debug Utilities

[](#seo-and-debug-utilities)

```
// SEO-friendly filename
echo Str::seoFileName('My Document (2023).pdf'); // "my-document-2023.pdf"

// SEO-friendly URL
echo Str::seoUrl('Product Category & Items'); // "product-category-items"

// Debug helpers
Str::prettyLog($complexArray); // Pretty print with
Str::prettyLogExit($data); // Pretty print and exit
```

---

TwigHelper
----------

[](#twighelper)

Simplified Twig template engine integration.

### Configuration Options

[](#configuration-options-6)

```
TwigHelper::init([
    // Template directories (can be string or array)
    '/path/to/templates',

    // Namespaced paths
    [
        'admin' => '/path/to/admin/templates',
        'email' => '/path/to/email/templates'
    ]
], [
    // Twig environment options
    'cache' => '/path/to/cache',          // Template cache directory
    'auto_reload' => true,                // Auto-reload templates in dev
    'strict_variables' => false,          // Strict variable checking
    'debug' => true                       // Enable debug mode
]);
```

### Methods

[](#methods-14)

#### `init(string|array $paths = [], array $options = [], ?\Twig\Loader\LoaderInterface $loader = null): \Twig\Environment`

[](#initstringarray-paths---array-options---twigloaderloaderinterface-loader--null-twigenvironment)

Initialize Twig environment.

```
// Basic setup
TwigHelper::init('/path/to/templates');

// Multiple directories
TwigHelper::init([
    '/path/to/app/templates',
    '/path/to/shared/templates'
]);

// Namespaced templates
TwigHelper::init([
    'app' => '/path/to/app/templates',
    'admin' => '/path/to/admin/templates',
    '/path/to/shared/templates' // default namespace
]);

// With custom options
TwigHelper::init('/templates', [
    'cache' => '/tmp/twig',
    'auto_reload' => App::isLocal(),
    'strict_variables' => true
]);
```

#### `render(string $template, array $context = [], ?\Twig\Environment $environment = null): string`

[](#renderstring-template-array-context---twigenvironment-environment--null-string)

Render template.

```
// Basic rendering
$html = TwigHelper::render('page.html.twig', [
    'title' => 'Welcome',
    'user' => AuthManager::user()
]);

// Namespaced template
$html = TwigHelper::render('@admin/dashboard.html.twig', [
    'stats' => $dashboardStats
]);

// Complex context
$html = TwigHelper::render('product/detail.html.twig', [
    'product' => $product,
    'related' => $relatedProducts,
    'reviews' => $reviews,
    'user_can_review' => AuthManager::isLoggedIn()
]);
```

#### `addGlobal(string $name, mixed $value, ?\Twig\Environment $environment = null): void`

[](#addglobalstring-name-mixed-value-twigenvironment-environment--null-void)

Add global variable.

```
// Make current user available everywhere
TwigHelper::addGlobal('current_user', AuthManager::user());

// Application config
TwigHelper::addGlobal('app_name', Config::get('app.name'));
TwigHelper::addGlobal('app_version', '1.0.0');

// Utility functions
TwigHelper::addGlobal('is_local', App::isLocal());
```

#### `addFunction(string $name, callable $callable, array $options = [], ?\Twig\Environment $environment = null): void`

[](#addfunctionstring-name-callable-callable-array-options---twigenvironment-environment--null-void)

Register custom function.

```
// Simple function
TwigHelper::addFunction('asset_url', function($path) {
    return '/assets/' . ltrim($path, '/');
});

// Function with context access
TwigHelper::addFunction('can', function($permission) {
    $user = AuthManager::user();
    return $user && in_array($permission, $user['permissions'] ?? []);
}, ['needs_context' => false]);

// Safe HTML function
TwigHelper::addFunction('render_widget', function($widgetName, $data) {
    return WidgetRenderer::render($widgetName, $data);
}, ['is_safe' => ['html']]);
```

#### `addFilter(string $name, callable $callable, array $options = [], ?\Twig\Environment $environment = null): void`

[](#addfilterstring-name-callable-callable-array-options---twigenvironment-environment--null-void)

Register custom filter.

```
// Custom formatting filter
TwigHelper::addFilter('currency', function($amount, $currency = 'USD') {
    return Format::currency($amount, $currency);
});

// String manipulation filter
TwigHelper::addFilter('excerpt', function($text, $length = 100) {
    return Str::words($text, $length);
});

// Usage in templates:
// {{ price|currency('EUR') }}
// {{ article.content|excerpt(50) }}
```

#### `addPath(string $path, ?string $namespace = null, ?\Twig\Environment $environment = null): void`

[](#addpathstring-path-string-namespace--null-twigenvironment-environment--null-void)

Add template directory.

```
// Add to default namespace
TwigHelper::addPath('/path/to/new/templates');

// Add namespaced path
TwigHelper::addPath('/path/to/plugins/templates', 'plugins');
```

### Built-in Filters and Functions

[](#built-in-filters-and-functions)

TwigHelper automatically registers many useful filters and functions:

**Filters:**

- `bytes` - Format::bytes()
- `currency` - Format::currency()
- `ago` - Date::ago()
- `slug` - Str::slug()
- `camel` - Str::camel()
- `snake` - Str::snake()
- `limit` - Str::limit()
- `json_pretty` - Format::json()

**Functions:**

- `format_date` - Date::format()
- `array_get` - Arrays::get()
- `format_bytes` - Format::bytes()
- `with_query_params` - Add/modify URL parameters

**Usage in templates:**

```
{# Format file size #}
File size: {{ file.size|bytes }}

{# Format currency #}
Price: {{ product.price|currency('EUR') }}

{# Relative time #}
Posted {{ post.created_at|ago }}

{# Array access with dot notation #}
{{ array_get(config, 'app.name') }}

{# URL manipulation #}
Next Page
Sort by Name
```

---

Best Practices
--------------

[](#best-practices)

### Database Usage

[](#database-usage)

```
// Always initialize DB connection first
DB::sqlite(':memory:');

// Use transactions for multiple operations
DB::transaction(function() {
    $userId = DB::insert('users', $userData);
    DB::insert('profiles', array_merge($profileData, ['user_id' => $userId]));
    return $userId;
});

// Use upsert for insert-or-update scenarios
DB::upsert('settings', [
    'key' => 'theme',
    'value' => 'dark',
    'updated_at' => date('Y-m-d H:i:s')
], 'key');
```

### Error Handling

[](#error-handling)

```
// Enable pretty errors in development
if (App::isLocal()) {
    PrettyErrorHandler::init([
        'overlay' => true,
        'log_errors' => true
    ]);
}
```

### Logging

[](#logging)

```
// Set up logging with defaults
Logs::init([
    'context_defaults' => [
        'application' => 'MyApp',
        'environment' => App::isProduction() ? 'prod' : 'dev',
        'user_id' => AuthManager::user()['id'] ?? null,
    ],
    'meta_defaults' => [
        'request_id' => Request::id(),
    ],
]);

// Create table once
Logs::createLogsTable();

// Log throughout your application
Logs::info('User logged in', ['user_id' => $user['id']]);
Logs::warning('API rate limit approaching', ['current' => 480, 'limit' => 500]);
```

### String Processing

[](#string-processing)

```
// Chain string operations
$slug = Str::slug(Str::limit($title, 50));

// Safe file naming
$filename = Str::seoFileName($userInput) . '.' . $extension;

// Validation
if (Str::isJson($input)) {
    $data = json_decode($input, true);
}
```

### Template Organization

[](#template-organization)

```
// Organize templates by feature
TwigHelper::init([
    'user' => '/templates/user',
    'admin' => '/templates/admin',
    'email' => '/templates/email',
    '/templates/shared' // default namespace
]);

// Use globals for common data
TwigHelper::addGlobal('site_name', Config::get('site.name'));
TwigHelper::addGlobal('current_user', AuthManager::user());
```

---

Date
----

[](#date-1)

The Date class provides utilities for formatting dates and times with human-friendly options.

#### `ago(\DateTimeInterface|int|string $timestamp, bool $full = false): string`

[](#agodatetimeinterfaceintstring-timestamp-bool-full--false-string-1)

Human friendly relative time (e.g., "2 hours ago", "in 3 days").

```
use PhpHelper\Date;

echo Date::ago('2023-01-01'); // "11 months ago"
echo Date::ago(time() - 3600); // "1 hour ago"
echo Date::ago('2023-12-25', true); // "1 year, 2 months and 3 days ago"
```

#### `format(\DateTimeInterface|int|string $timestamp, string $format = 'datetime', ?string $timezone = null): string`

[](#formatdatetimeinterfaceintstring-timestamp-string-format--datetime-string-timezone--null-string-1)

Easy date/time formatting with sensible presets.

```
$date = '2023-12-25 15:30:45';

echo Date::format($date); // "2023-12-25 15:30"
echo Date::format($date, 'date'); // "2023-12-25"
echo Date::format($date, 'human'); // "25 Dec 2023"
echo Date::format($date, 'iso'); // ISO 8601 format
echo Date::format($date, 'Y-m-d H:i:s', 'America/New_York'); // With timezone
```

#### `timestamp(\DateTimeInterface|int|string|null $value = null, ?string $timezone = null): int`

[](#timestampdatetimeinterfaceintstringnull-value--null-string-timezone--null-int-1)

Get a UNIX timestamp from various input types.

```
echo Date::timestamp(); // Current timestamp
echo Date::timestamp('2023-12-25'); // Timestamp for date
echo Date::timestamp('2023-12-25 15:30', 'Europe/London'); // With timezone
```

---

Files
-----

[](#files-1)

The Files class provides comprehensive file and directory operations.

#### `read(string $path): string|false`

[](#readstring-path-stringfalse-1)

Read file contents.

```
use PhpHelper\Files;

$content = Files::read('/path/to/file.txt');
if ($content !== false) {
    echo $content;
}
```

#### `write(string $path, string $content, int $flags = 0): int|false`

[](#writestring-path-string-content-int-flags--0-intfalse-1)

Write contents to file (creates directories if needed).

```
$bytes = Files::write('/path/to/file.txt', 'Hello World');
$bytes = Files::write('/path/to/file.txt', 'Append this', FILE_APPEND);
```

#### `append(string $path, string $content): int|false`

[](#appendstring-path-string-content-intfalse-1)

Append contents to file.

```
Files::append('/path/to/log.txt', "New log entry\n");
```

#### `delete(string $path): bool`

[](#deletestring-path-bool-1)

Delete file.

```
if (Files::delete('/path/to/old-file.txt')) {
    echo "File deleted successfully";
}
```

#### `copy(string $source, string $dest): bool`

[](#copystring-source-string-dest-bool-1)

Copy file (creates destination directories if needed).

```
Files::copy('/source/file.txt', '/backup/file.txt');
```

#### `move(string $source, string $dest): bool`

[](#movestring-source-string-dest-bool-1)

Move/rename file.

```
Files::move('/old/path/file.txt', '/new/path/file.txt');
```

#### `download(string $url, string $savePath): bool`

[](#downloadstring-url-string-savepath-bool-1)

Download a file from a URL to a local path.

```
if (!Files::download('https://example.com/file.zip', '/path/to/file.zip')) {
    echo "Download failed";
}
```

#### `exists(string $path): bool`

[](#existsstring-path-bool-1)

Check if file exists.

```
if (Files::exists('/path/to/file.txt')) {
    echo "File exists";
}
```

#### `size(string $path): int|false`

[](#sizestring-path-intfalse-1)

Get file size in bytes.

```
$bytes = Files::size('/path/to/file.txt');
echo "File size: $bytes bytes";
```

#### `extension(string $path): string`

[](#extensionstring-path-string-1)

Get file extension.

```
echo Files::extension('/path/to/document.pdf'); // "pdf"
```

#### `mimeType(string $path): string|false`

[](#mimetypestring-path-stringfalse-1)

Get file MIME type.

```
echo Files::mimeType('/path/to/image.jpg'); // "image/jpeg"
```

#### `modifiedTime(string $path): int|false`

[](#modifiedtimestring-path-intfalse)

Get file modification time.

```
$timestamp = Files::modifiedTime('/path/to/file.txt');
echo date('Y-m-d H:i:s', $timestamp);
```

#### `createDirectory(string $path, int $permissions = 0755): bool`

[](#createdirectorystring-path-int-permissions--0755-bool-1)

Create directory recursively.

```
Files::createDirectory('/path/to/new/directory');
```

#### `deleteDirectory(string $path): bool`

[](#deletedirectorystring-path-bool-1)

Delete directory recursively.

```
Files::deleteDirectory('/path/to/directory');
```

#### `listFiles(string $path, string $pattern = '*'): array`

[](#listfilesstring-path-string-pattern---array-1)

List files in directory.

```
$files = Files::listFiles('/path/to/directory');
$phpFiles = Files::listFiles('/src', '*.php');
```

#### `listDirectories(string $path): array`

[](#listdirectoriesstring-path-array)

List directories.

```
$dirs = Files::listDirectories('/path/to/parent');
```

#### `readJson(string $path): mixed`

[](#readjsonstring-path-mixed-1)

Read JSON file.

```
$data = Files::readJson('/path/to/data.json');
```

#### `writeJson(string $path, mixed $data, int $flags = JSON_PRETTY_PRINT): int|false`

[](#writejsonstring-path-mixed-data-int-flags--json_pretty_print-intfalse-1)

Write JSON file.

```
$data = ['name' => 'John', 'age' => 30];
Files::writeJson('/path/to/data.json', $data);
```

#### `readCsv(string $path, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): array|false`

[](#readcsvstring-path-string-delimiter---string-enclosure---string-escape---arrayfalse-1)

Read CSV file.

```
$rows = Files::readCsv('/path/to/data.csv');
```

#### `writeCsv(string $path, array $data, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): bool`

[](#writecsvstring-path-array-data-string-delimiter---string-enclosure---string-escape---bool-1)

Write CSV file.

```
$data = [
    ['Name', 'Age', 'City'],
    ['John', 30, 'New York'],
    ['Jane', 25, 'London']
];
Files::writeCsv('/path/to/data.csv', $data);
```

#### `hash(string $path, string $algo = 'sha256'): string|false`

[](#hashstring-path-string-algo--sha256-stringfalse-1)

Get file hash.

```
$hash = Files::hash('/path/to/file.txt');
$md5 = Files::hash('/path/to/file.txt', 'md5');
```

#### `isAbsolute(string $path): bool`

[](#isabsolutestring-path-bool)

Check if path is absolute.

```
echo Files::isAbsolute('/absolute/path'); // true
echo Files::isAbsolute('relative/path'); // false
```

#### `normalizePath(string $path): string`

[](#normalizepathstring-path-string)

Normalize path separators.

```
echo Files::normalizePath('path\\to\\file'); // Uses correct separator for OS
```

#### `joinPaths(string ...$parts): string`

[](#joinpathsstring-parts-string)

Join path parts.

```
$path = Files::joinPaths('/base', 'subdir', 'file.txt');
// Result: "/base/subdir/file.txt" (with correct separators)
```

---

Format
------

[](#format-1)

The Format class provides utilities for formatting numbers, bytes, currency, and other data types.

#### `bytes(int $bytes, int $precision = 2, string $system = 'binary', ?array $units = null): string`

[](#bytesint-bytes-int-precision--2-string-system--binary-array-units--null-string-1)

Format bytes into human readable string.

```
use PhpHelper\Format;

echo Format::bytes(1536); // "1.50 KB"
echo Format::bytes(1048576, 1, 'binary'); // "1.0 MB"
echo Format::bytes(1000000, 2, 'si'); // "1.00 MB" (1000-based)
echo Format::bytes(1024, 0, 'iec'); // "1 KiB"
```

#### `number(float|int $value, int $decimals = 0, string $decimalPoint = '.', string $thousandsSep = ','): string`

[](#numberfloatint-value-int-decimals--0-string-decimalpoint---string-thousandssep---string-1)

Standard number formatting.

```
echo Format::number(1234567.89, 2); // "1,234,567.89"
echo Format::number(1234567.89, 0); // "1,234,568"
```

#### `currency(float $amount, string $currency = 'USD', ?string $locale = null, ?int $precision = null): string`

[](#currencyfloat-amount-string-currency--usd-string-locale--null-int-precision--null-string-1)

Format currency amount.

```
echo Format::currency(1234.56); // "$1,234.56" (if intl available)
echo Format::currency(1234.56, 'EUR', 'de_DE'); // "1.234,56 €"
echo Format::currency(1234.56, 'USD', null, 0); // "$1,235"
```

#### `percent(float $value, int $precision = 0, bool $fromFraction = true): string`

[](#percentfloat-value-int-precision--0-bool-fromfraction--true-string-1)

Format percentage.

```
echo Format::percent(0.1234); // "12%" (from fraction)
echo Format::percent(12.34, 1, false); // "12.3%" (from percentage)
```

#### `shortNumber(float|int $value, int $precision = 1): string`

[](#shortnumberfloatint-value-int-precision--1-string-1)

Humanized abbreviations.

```
echo Format::shortNumber(1200); // "1.2K"
echo Format::shortNumber(1500000); // "1.5M"
echo Format::shortNumber(2800000000); // "2.8B"
```

#### `duration(int $seconds, bool $compact = true): string`

[](#durationint-seconds-bool-compact--true-string-1)

Human time spans.

```
echo Format::duration(3661); // "1h 1m 1s"
echo Format::duration(3661, false); // "1 hour, 1 minute, 1 second"
```

#### `hms(int $seconds, bool $withDays = false): string`

[](#hmsint-seconds-bool-withdays--false-string-1)

Clock format HH:MM:SS.

```
echo Format::hms(3661); // "01:01:01"
echo Format::hms(90061, true); // "1d 01:01:01"
```

#### `ordinal(int $number): string`

[](#ordinalint-number-string-1)

English ordinal suffix.

```
echo Format::ordinal(1); // "1st"
echo Format::ordinal(22); // "22nd"
echo Format::ordinal(103); // "103rd"
```

#### `parseBytes(string $size): int`

[](#parsebytesstring-size-int-1)

Parse human-readable size into bytes.

```
echo Format::parseBytes('2M'); // 2097152
echo Format::parseBytes('1.5 GB'); // 1610612736
echo Format::parseBytes('2MiB'); // 2097152
```

#### `bool(mixed $value, string $true = 'Yes', string $false = 'No', string $null = ''): string`

[](#boolmixed-value-string-true--yes-string-false--no-string-null---string-1)

Consistent boolean labels.

```
echo Format::bool(true); // "Yes"
echo Format::bool(0); // "No"
echo Format::bool('1', 'Active', 'Inactive'); // "Active"
```

#### `json(mixed $value, bool $pretty = true, int $flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES): string`

[](#jsonmixed-value-bool-pretty--true-int-flags--json_unescaped_unicode--json_unescaped_slashes-string-1)

JSON encode for display.

```
$data = ['name' => 'John', 'age' => 30];
echo Format::json($data); // Pretty formatted JSON
echo Format::json($data, false); // Compact JSON
```

---

Http
----

[](#http-1)

The Http class provides utilities for HTTP operations, redirects, downloads, and client information.

#### `redirect(string $url, int $statusCode = 302, bool $exit = true): void`

[](#redirectstring-url-int-statuscode--302-bool-exit--true-void-1)

Redirect to a URL.

```
use PhpHelper\Http;

Http::redirect('/dashboard');
Http::redirect('https://example.com', 301);
Http::redirect('/login', 302, false); // Don't exit after redirect
```

#### `download(string $filename, string $mimetype = 'application/octet-stream')`

[](#downloadstring-filename-string-mimetype--applicationoctet-stream-1)

Stream a file as download.

```
Http::download('/path/to/file.pdf', 'application/pdf');
Http::download('/path/to/image.jpg', 'image/jpeg');
```

#### `json(mixed $data, int $status = 200, array $headers = []): void`

[](#jsonmixed-data-int-status--200-array-headers---void-1)

Send JSON response.

```
$data = ['success' => true, 'message' => 'Data saved'];
Http::json($data);
Http::json(['error' => 'Not found'], 404);
Http::json($data, 200, ['X-Custom-Header' => 'value']);
```

#### `clientInfo(): array`

[](#clientinfo-array-1)

Collect comprehensive client information.

```
$info = Http::clientInfo();

echo $info['ip']; // Client IP
echo $info['browser']; // Browser name
echo $info['os']; // Operating system
echo $info['device']; // Device type (mobile/tablet/desktop/bot)
echo $info['user_agent']; // Full user agent string

// Check device types
if ($info['is_mobile']) {
    echo "Mobile device detected";
}

// Language preferences
$languages = $info['languages']; // Array of preferred languages

// Request information
echo $info['method']; // HTTP method
echo $info['url']; // Full URL
echo $info['referer']; // Referring URL
```

---

Logs
----

[](#logs-1)

The Logs class provides structured database logging with multiple severity levels.

#### `init(array $config = []): void`

[](#initarray-config---void-3)

Initialize the logger with configuration.

```
use PhpHelper\Logs;

Logs::init([
    'table' => 'application_logs',
    'context_defaults' => ['app' => 'myapp'],
    'meta_defaults' => ['version' => '1.0']
]);
```

#### `log(string $level, string $message, array $context = [], array $meta = []): string`

[](#logstring-level-string-message-array-context---array-meta---string-1)

Log a message with custom level.

```
$id = Logs::log('info', 'User logged in', ['user_id' => 123], ['ip' => '192.168.1.1']);
```

#### Convenience Methods

[](#convenience-methods)

All standard log levels are available as methods:

```
Logs::debug('Debug information', ['query' => $sql]);
Logs::info('Information message', ['user_id' => 123]);
Logs::success('Operation completed successfully');
Logs::notice('Notice: Cache cleared');
Logs::warning('Warning: Disk space low', ['available' => '10GB']);
Logs::error('Database connection failed', ['host' => 'db.server']);
Logs::critical('Critical system error', ['service' => 'payment']);
Logs::alert('Alert: Security breach detected');
Logs::emergency('Emergency: System shutdown required');
```

#### `createLogsTable(?string $table = null): void`

[](#createlogstablestring-table--null-void-1)

Create the logs table (MySQL and SQLite supported).

```
Logs::createLogsTable(); // Uses default table name
Logs::createLogsTable('custom_logs'); // Custom table name
```

#### Configuration Methods

[](#configuration-methods)

```
Logs::setTable('custom_logs');
Logs::setContextDefaults(['app' => 'myapp', 'env' => 'production']);
Logs::setMetaDefaults(['server' => $_SERVER['SERVER_NAME']]);
Logs::clearDefaults();
```

---

PrettyErrorHandler
------------------

[](#prettyerrorhandler-1)

The PrettyErrorHandler class provides beautiful error pages for development with code context and stack traces.

#### `__construct(array $options = [], bool $registerGlobal = true)`

[](#__constructarray-options---bool-registerglobal--true-1)

Create and optionally register error handler.

```
use PhpHelper\PrettyErrorHandler;

// Simple initialization
$handler = new PrettyErrorHandler();

// With custom options
$handler = new PrettyErrorHandler([
    'display' => true,
    'show_trace' => true,
    'overlay' => true,
    'context_before' => 8,
    'context_after' => 6,
    'skip_warnings' => false,
    'log_errors' => true
], false); // Don't auto-register
$handler->register(); // Register manually
```

#### `init(array $options = []): self`

[](#initarray-options---self-1)

Static convenience method.

```
PrettyErrorHandler::init([
    'overlay' => false, // Full page instead of overlay
    'show_trace' => false, // Hide stack trace
    'log_errors' => true // Log to pretty_errors.txt
]);
```

#### `enable(array $options = []): self`

[](#enablearray-options---self)

Enable (or re-enable) the global handler. Any previously active instance is disabled before applying the new settings.

```
$handler = PrettyErrorHandler::enable(['show_trace' => false]);
```

#### `disable(): void`

[](#disable-void)

Disable the currently active handler and restore the previous PHP error settings.

```
PrettyErrorHandler::disable();
```

#### Available Options:

[](#available-options)

- `display` (bool): Force display errors (default: true)
- `report` (int): Error reporting level (default: E\_ALL)
- `context_before` (int): Lines before error (default: 6)
- `context_after` (int): Lines after error (default: 4)
- `show_trace` (bool): Include stack trace (default: true)
- `overlay` (bool): Render as overlay vs full page (default: true)
- `skip_warnings` (bool): Skip PHP warnings (default: false)
- `log_errors` (bool): Log to pretty\_errors.txt (default: false)

---

Additional Str Methods
----------------------

[](#additional-str-methods)

The Str class has additional utility methods not previously documented:

#### `seoFileName(string $text): string`

[](#seofilenamestring-text-string)

Create SEO-friendly filename (keeps dots).

```
use PhpHelper\Str;

echo Str::seoFileName('My Document File.pdf'); // "my-document-file.pdf"
echo Str::seoFileName('Αρχείο με Ελληνικά.doc'); // "archeio-me-ellinika.doc"
```

#### `seoUrl(string $text): string`

[](#seourlstring-text-string)

Create SEO-friendly URL (removes dots).

```
echo Str::seoUrl('My Article Title!'); // "my-article-title"
echo Str::seoUrl('Product v2.0 Launch'); // "product-v2-0-launch"
```

#### Debug Helper Methods

[](#debug-helper-methods)

#### `prettyLog(mixed $v): void`

[](#prettylogmixed-v-void)

Pretty print variable with HTML formatting.

```
Str::prettyLog($array); // Outputs formatted array in  tags
```

#### `prettyLogExit(mixed $v): void`

[](#prettylogexitmixed-v-void)

Pretty print and exit with black background.

```
Str::prettyLogExit($debugData); // Debug and stop execution
```

#### `print_functions(object $obj): void`

[](#print_functionsobject-obj-void)

Display all methods of an object.

```
Str::print_functions($myObject); // Shows all available methods
```

---

Example index.php
-----------------

[](#example-indexphp)

```
