NSY Libraries — User Tutorial
A practical guide to the bundled System\Libraries\* helper classes. Every method
is static, so no instantiation is needed. The guide is split into five
self-contained parts:
- Part A —
File— file-system management - Part B —
LanguageCode— ISO 639-1 language codes - Part C —
LoadTime— request execution timer - Part D —
Request— input reading and sanitizing - Part E —
Validate— scalar validation helpers
Companion libraries:
Json·Cookie·Encryption·Session·Curl— native, dependency-free classes inSystem\Libraries. Rule-based validation is covered inValidation(rakit/validationvia theSystem\Libraries\Validatoralias).
Table of Contents
Part A — File Library
- Getting Started
- Checking Existence —
exists() - Writing Files —
writeFile() - Deleting a File —
delete() - Creating Directories —
createDir() - Copying a Directory Tree —
copyDirRecursively() - Deleting Directories
- Iterating a Directory —
getFilesFromDir() - Listing Filenames Recursively —
getFilenames() - Directory Report —
getDirFileInfo() - Single File Report —
getFileInfo() - MIME Type by Extension —
getMimeByExtension() - Complete Example — Upload Handler
- File Quick Reference
Part B — LanguageCode Library
- Getting Started
- List Every Language —
get() - Name from Code —
getLanguageFromCode() - Code from Name —
getCodeFromLanguage() - Application Helpers
- Complete Example — Language Dropdown
- LanguageCode Quick Reference
Part C — LoadTime Library
Part D — Request Library
- Which Method Is This?
- Reading Input —
input() - Sanitizing to Array / Object / JSON
- Sanitizing Single Values
- Content Type
- One-Shot Readers (via Input)
- Request Quick Reference
Part E — Validate Library
- Sanitizing Whole Values
- Strings, Integers, Floats, Booleans
- IP, URL and Email
- Validate Quick Reference
Getting Started
Import the class, then call any method statically:
use System\Libraries\File;
if (File::exists('/var/www/html/storage/report.pdf')) {
echo 'Found it!';
}
The class is PSR-4 autoloaded (
System\→System/), so it works anywhere afterSystem/Vendor/autoload.phpis loaded — controllers, models, routes, CLI scripts.
Checking Existence — exists()
Works with local paths and URLs.
// Local file → true only if the path is an actual file (not a directory)
File::exists('/var/www/html/storage/report.pdf'); // bool
// Remote URL → performs a HEAD request (5s timeout), true for HTTP 2xx–3xx
File::exists('https://example.com/logo.png'); // bool
Remote checks time out after 5 seconds and return
falseon failure — safe to call in a request path.
Signature: exists(string $file): bool
Writing Files — writeFile()
Creates the file if missing, overwrites otherwise. Uses an exclusive lock
(LOCK_EX), so concurrent writes are safe.
$ok = File::writeFile('/var/www/html/storage/hello.txt', "Hello, NSY!\n");
if (!$ok) {
echo 'Could not write the file (check directory permissions).';
}
Append mode instead of overwrite:
File::writeFile('/var/www/html/storage/app.log', "new line\n", 'ab');
Signature: writeFile(string $path, string $data, string $mode = 'wb'): bool
Deleting a File — delete()
Returns false when the file does not exist (nothing to delete).
if (File::delete('/var/www/html/storage/old-report.pdf')) {
echo 'Deleted.';
} else {
echo 'File was already gone.';
}
Signature: delete(string $file): bool
Creating Directories — createDir()
Creates nested directories recursively (mkdir(..., 0777, true)).
File::createDir('/var/www/html/storage/uploads/2026/09');
Returns
falseif the directory already exists — that is the normal "nothing to do" signal, not an error. Check withis_dir()first if you need to tell the two cases apart.
Signature: createDir(string $path): bool
Copying a Directory Tree — copyDirRecursively()
Copies all files including subdirectories from one place to another.
$ok = File::copyDirRecursively(
'/var/www/html/storage/templates',
'/var/www/html/storage/templates-backup'
);
if (!$ok) {
echo 'Copy failed partway — check permissions and disk space.';
}
Signature: copyDirRecursively(string $from, string $to): bool
Deleting Directories
Two methods, pick the right one:
// Removes a directory ONLY if it is empty
File::deleteEmptyDir('/var/www/html/storage/empty-folder'); // bool
// Removes a directory WITH everything inside it (files + subfolders)
File::deleteDirRecursively('/var/www/html/storage/cache'); // bool
deleteDirRecursively()also removes the top-level directory itself, and returnsfalseif the path is not a directory.
Signatures:
File::deleteEmptyDir(string $path): bool
File::deleteDirRecursively(string $path): bool
Iterating a Directory — getFilesFromDir()
Returns a \DirectoryIterator for manual loops, or false if the path is
not a directory.
$iterator = File::getFilesFromDir('/var/www/html/storage');
if ($iterator !== false) {
foreach ($iterator as $item) {
if ($item->isDot()) {
continue; // skip "." and ".."
}
echo $item->getFilename() . PHP_EOL;
}
}
Signature: getFilesFromDir(string $path): object|false
Listing Filenames Recursively — getFilenames()
Returns a flat array of every filename under a directory (subfolders included, dot-files skipped).
// Plain filenames
$names = File::getFilenames('/var/www/html/storage');
print_r($names);
// Array ( [0] => report.pdf [1] => hello.txt ... )
// With full paths
$paths = File::getFilenames('/var/www/html/storage', true);
The third parameter (
$_recursion) is for internal use — never pass it. Returnsfalseif the directory cannot be opened.
Signature: getFilenames(string $source_dir, bool $include_path = false, bool $_recursion = false): mixed
Directory Report — getDirFileInfo()
Like getFilenames(), but each entry carries size, date and permissions info.
$info = File::getDirFileInfo('/var/www/html/storage');
foreach ($info as $entry) {
echo $entry['name'] . ' — ' . $entry['size'] . ' bytes' . PHP_EOL;
}
// Each entry: name, server_path, size, date, relative_path
Pass false as second argument to descend into subdirectories too (default
is top level only):
$all = File::getDirFileInfo('/var/www/html/storage', false);
Signature: getDirFileInfo(string $source_dir, bool $top_level_only = true, bool $_recursion = false): mixed
Single File Report — getFileInfo()
Returns name, path, size and modification date by default; ask for more with the second parameter (array or comma-separated string).
$info = File::getFileInfo('/var/www/html/storage/report.pdf');
print_r($info);
// Array ( [name] => report.pdf [server_path] => ... [size] => 48211 [date] => 1789532251 )
// Custom fields
$info = File::getFileInfo($path, ['name', 'size', 'readable', 'writable']);
// or: File::getFileInfo($path, 'name,size,readable,writable');
Available keys: name, server_path, size, date, readable,
writable, executable, fileperms. Returns false if the file is missing,
and an empty array [] when none of the requested keys match.
Signature: getFileInfo(string $file, mixed $returned_values = [...]): array|false
MIME Type by Extension — getMimeByExtension()
Looks up System/Config/Mimes.php. Matching is case-insensitive; when an
extension maps to several types, the first one is returned.
File::getMimeByExtension('photo.JPG'); // "image/jpeg"
File::getMimeByExtension('data.csv'); // "text/x-comma-separated-values"
File::getMimeByExtension('archive.unknownext'); // false
File::getMimeByExtension('no-extension'); // false
Convenience only — an extension says nothing about actual file content. Never use this for security decisions (e.g. validating uploads); inspect the content instead (e.g.
finfo/mime_content_type()).
Need the whole map? File::getMimes() returns the full extension → type
array from the config file.
Signatures:
File::getMimeByExtension(string $filename): string|false
File::getMimes(): array
Complete Example — Simple Upload Handler Sketch
use System\Libraries\File;
$uploadDir = '/var/www/html/storage/uploads';
// 1. Make sure the target directory exists
if (!is_dir($uploadDir)) {
File::createDir($uploadDir);
}
// 2. Move the uploaded file, then verify it
move_uploaded_file($_FILES['doc']['tmp_name'], $uploadDir . '/doc.pdf');
if (!File::exists($uploadDir . '/doc.pdf')) {
die('Upload failed.');
}
// 3. Inspect and report
$info = File::getFileInfo($uploadDir . '/doc.pdf', ['name', 'size', 'date']);
echo $info['name'] . ' (' . $info['size'] . ' bytes) stored successfully.';
File Quick Reference
| Method | Purpose | Returns |
|---|---|---|
File::exists($file) |
File or URL exists? | bool |
File::writeFile($path,$data,$mode) |
Write (locked) / create file | bool |
File::delete($file) |
Delete one file | bool |
File::createDir($path) |
Create dirs recursively | bool |
File::copyDirRecursively($from,$to) |
Copy whole tree | bool |
File::deleteEmptyDir($path) |
Remove empty dir | bool |
File::deleteDirRecursively($path) |
Remove dir with contents | bool |
File::getFilesFromDir($path) |
Iterate with DirectoryIterator |
object|false |
File::getFilenames($dir,$include_path) |
Flat recursive filename list | array|false |
File::getDirFileInfo($dir,$top_only) |
Recursive file report | array|false |
File::getFileInfo($file,$fields) |
Single file report | array|false |
File::getMimeByExtension($f) |
Extension → MIME type | string|false |
File::getMimes() |
Full MIME map | array |
Related source: System/Libraries/File.php, MIME config at System/Config/Mimes.php.
Note (Option 2): Global helper shortcuts (
System/Core/NSY_Helpers_File.php—check_file(),create_file(), …) have been removed. UseSystem\Libraries\Filedirectly.
NSY LanguageCode Library — User Tutorial
A practical guide to the language-code library at
System/Libraries/LanguageCode.php (namespace System\Libraries, class
LanguageCode). It maps between ISO 639-1 language codes ('es', 'id',
'en-gb', …) and language names ('Spanish', 'Indonesian', …) using the
217-entry dataset in System/Libraries/LanguageCodeCollection.php. All
methods are static.
Getting Started with LanguageCode
use System\Libraries\LanguageCode;
echo LanguageCode::getLanguageFromCode('es'); // "Spanish"
PSR-4 autoloaded (
System\→System/), usable anywhere afterSystem/Vendor/autoload.phpis loaded.
List Every Language — get()
Returns the full code => name map (217 entries).
$languages = LanguageCode::get();
echo count($languages); // 217
foreach ($languages as $code => $name) {
echo "$code — $name" . PHP_EOL;
}
// es — Spanish
// id — Indonesian
// en-gb — English (United Kingdom)
// ...
Signature: get(): array
Name from Code — getLanguageFromCode()
Lookup is case-insensitive and trims surrounding whitespace, so user
input can be passed directly. Regional variants ('en-gb', 'ar-eg', …)
work as well. Returns false for unknown codes.
LanguageCode::getLanguageFromCode('es'); // "Spanish"
LanguageCode::getLanguageFromCode('ES'); // "Spanish"
LanguageCode::getLanguageFromCode('en-GB'); // "English (United Kingdom)"
LanguageCode::getLanguageFromCode(' id '); // "Indonesian"
$code = $_GET['lang'] ?? 'en';
$name = LanguageCode::getLanguageFromCode($code);
if ($name === false) {
die('Unsupported language code.');
}
echo "Selected language: $name";
Signature: getLanguageFromCode(string $languageCode): string|false
Code from Name — getCodeFromLanguage()
Reverse lookup, also case-insensitive. Exact-case matches take a fast
path; anything else falls back to a case-insensitive scan. Returns false
for unknown names.
LanguageCode::getCodeFromLanguage('Spanish'); // "es"
LanguageCode::getCodeFromLanguage('spanish'); // "es"
LanguageCode::getCodeFromLanguage('SPANISH'); // "es"
LanguageCode::getCodeFromLanguage('Klingon'); // false
Signature: getCodeFromLanguage(string $languageName): string|false
Application Helpers
get_lang_code() (dual-mode, defined in System/Core/NSY_Helpers_Global.php) wraps the library:
get_lang_code(); // "id-ID" — the application's own locale
get_lang_code('Spanish'); // "es" — lookup by language name
get_lang_code('Klingon'); // false — unknown name
<html lang="@( get_lang_code() )">in templates uses this helper. For all other language features useLanguageCode::directly.
Complete Example — Language Dropdown
use System\Libraries\LanguageCode;
$selected = $_GET['lang'] ?? 'en';
if (LanguageCode::getLanguageFromCode($selected) === false) {
$selected = 'en'; // fall back to a safe default
}
echo '<select name="lang">';
foreach (LanguageCode::get() as $code => $name) {
$isSelected = ($code === $selected) ? ' selected' : '';
echo "<option value=\"$code\"$isSelected>$name</option>";
}
echo '</select>';
LanguageCode Quick Reference
| Method / Helper | Purpose | Returns |
|---|---|---|
LanguageCode::get() |
Full 217-entry code → name map | array |
LanguageCode::getLanguageFromCode($code) |
Name from code (case-insensitive) | string|false |
LanguageCode::getCodeFromLanguage($name) |
Code from name (case-insensitive) | string|false |
get_lang_code() |
Application locale | string |
get_lang_code($name) |
Lookup via LanguageCode |
string|false |
Related source: System/Libraries/LanguageCode.php, dataset in System/Libraries/LanguageCodeCollection.php.
get_lang_code() lives in System/Core/NSY_Helpers_Global.php.
NSY LoadTime Library — User Tutorial
A practical guide to the stopwatch library at
System/Libraries/LoadTime.php (namespace System\Libraries, class
LoadTime). It measures how long a block of code takes — handy for footer
timers ("Page generated in 0.0423 seconds") or quick profiling. All
methods are static.
Measuring Execution Time
Start the timer, run your code, then read the elapsed seconds:
use System\Libraries\LoadTime;
LoadTime::start();
// ... code you want to measure ...
usleep(1500);
$seconds = LoadTime::end(); // e.g. 0.0016
echo "Done in $seconds seconds.";
Rules worth knowing:
LoadTime::isActive(); // false — timer not running
LoadTime::end(); // false — nothing was started, safe to call
LoadTime::start();
LoadTime::isActive(); // true
LoadTime::end(); // float, e.g. 0.0234
LoadTime::isActive(); // false — end() resets the timer (one-shot)
The timer is one-shot: every
end()stops and resets it, so callstart()again for the next measurement.
Signatures:
LoadTime::start(): float
LoadTime::end(): float|false
LoadTime::isActive(): bool
Usage
use System\Libraries\LoadTime;
LoadTime::start();
// ... measured code ...
echo 'Rendered in ' . LoadTime::end() . ' seconds.';
if (LoadTime::isActive()) { /* timer still running */ }
LoadTime Quick Reference
| Method | Purpose | Returns |
|---|---|---|
LoadTime::start() |
Start (or restart) the timer | float (microtime) |
LoadTime::end() |
Stop, reset, read elapsed seconds | float|false |
LoadTime::isActive() |
Is the timer running? | bool |
Related source: System/Libraries/LoadTime.php.
NSY Request Library — User Tutorial
A practical guide to the HTTP-input library at
System/Libraries/Request.php (namespace System\Libraries, class
Request). It answers "which method is this?", reads GET/POST/PUT/DELETE
input, and sanitizes values through the Validate library (Part E).
Which Method Is This?
use System\Libraries\Request;
if (Request::isPost()) {
// handle form submission
}
Request::isGet(); // bool
Request::isPut(); // bool
Request::isDelete(); // bool
Signatures: Request::isGet(): bool (same shape for isPost/isPut/isDelete)
The checks read
$_SERVER['REQUEST_METHOD']and safely returnfalsewhen it is missing (e.g. CLI).
Reading Input — input()
Pick a source — 'GET', 'POST', 'PUT' or 'DELETE' (case-insensitive)
— and you get back a small reader function. Call it with a key to select a
value, then sanitize it with any as*() method:
$get = Request::input('GET');
$name = $get('name')->asString('guest'); // "guest" when missing
$page = $get('page')->asInteger(1); // 1 when missing/invalid
Things to know:
- The type name is case-insensitive:
Request::input('get')works. - Each
($key)call returns an independent object, so holding twoselections is safe:
$a = $get('x'); $b = $get('y');— reading$alater still gives youx. - Other method names (e.g.
'PATCH') yield an empty input set rather thancrashing.
PUT/DELETEbodies are parsed fromphp://input(JSON, form-encodedand multipart supported); an empty body simply yields an empty set.
Signature: Request::input(string $type): callable
Sanitizing to Array / Object / JSON
Read the whole input (or one key) and convert it in one step. The optional
$filters map declares the expected type per key; $default fills in
missing or invalid values:
$post = Request::input('POST');
$user = $post()->asArray(
['name' => 'string', 'age' => 'integer', 'email' => 'email'],
'n/a'
);
// ['name' => ..., 'age' => ..., 'email' => ...]
$obj = $post()->asObject(['name' => 'string']);
$json = $post('items')->asJson(); // one key, encoded back to JSON
Valid filter names: array, object, string, integer, float,
boolean, ip, url, email (each maps to the matching as*() method
from Part E).
Signatures:
$post()->asArray(array $filters = [], $default = null): array
$post()->asObject(array $filters = [], $default = null): \stdClass
$post()->asJson(mixed $default = null): mixed
Sanitizing Single Values
Each method reads the selected key and coerces it, falling back to
$default when the key is missing or invalid:
$get = Request::input('GET');
$get('name')->asString('guest'); // tags stripped, quotes kept
$get('page')->asInteger(1); // int or 1
$get('ratio')->asFloat(0.0); // float or 0.0
$get('active')->asBoolean(false); // bool or false
$get('ip')->asIp(); // valid IP or null
$get('site')->asUrl(); // sanitized URL or null
$get('mail')->asEmail(); // valid email or null
Signatures (same shape for every method):
$get('key')->asString(mixed $default = null): mixed
// asInteger / asFloat / asBoolean / asIp / asUrl / asEmail likewise
Content Type
Request::getContentType(); // e.g. "application/json"
Reads the Content-Type request header with any ; charset=… suffix
removed. Returns "" when the header is absent.
Signature: Request::getContentType(): string
One-Shot Readers (via Input)
For convenience, keep using Request::input() directly — no helper needed:
$data = Request::input('POST')->asArray(['name' => 'string'], 'n/a');
$name = Request::input('GET')('name')->asString('guest');
Request Quick Reference
| Method | Purpose | Returns |
|---|---|---|
Request::isGet/isPost/isPut/isDelete() |
Current HTTP method? | bool |
Request::input($type) |
Reader for GET/POST/PUT/DELETE | callable |
$r()->asArray($filters,$default) |
Whole input as array | array |
$r()->asObject($filters,$default) |
Whole input as object | stdClass |
$r()->asJson($default) |
Input (or key) as JSON | mixed |
$r($key)->asString/asInteger/… |
Single sanitized value | mixed |
Request::getContentType() |
Content-Type without suffix | string |
Related source: System/Libraries/Request.php, sanitizers in System/Libraries/Validate.php.
NSY Validate Library — User Tutorial
A practical guide to the sanitizer library at
System/Libraries/Validate.php (namespace System\Libraries, class
Validate). Every method takes a value plus a $default that is returned
when the value is missing or invalid — so you always get something usable
back. All methods are static.
Sanitizing Whole Values
use System\Libraries\Validate;
Validate::asArray(['a' => 1]); // ['a' => 1]
Validate::asArray('not-array', 'dflt'); // "dflt"
Validate::asArray(5, 'dflt'); // "dflt" (scalar is not an array)
Validate::asObject(['a' => 1]); // stdClass { a: 1 }
Validate::asJson(['a' => 1]); // '{"a":1}'
Validate::asJson('already'); // "already" (strings pass through)
Signatures:
Validate::asArray(mixed $data, mixed $default = null): mixed
Validate::asObject(mixed $data, mixed $default = null): mixed
Validate::asJson(mixed $data, mixed $default = null): mixed
Strings, Integers, Floats, Booleans
Validate::asString('<b>hi</b>'); // "hi" (tags stripped, quotes kept)
Validate::asString('<a href="x">it"s</a>'); // 'it"s'
Validate::asString(123); // "123"
Validate::asString(null); // null (the default)
Validate::asInteger('42'); // 42
Validate::asInteger('abc', 'n/a'); // "n/a"
Validate::asFloat('1.5'); // 1.5
Validate::asFloat('x', 0.0); // 0.0
Validate::asBoolean('yes'); // true
Validate::asBoolean('no'); // false
Validate::asBoolean('maybe', 'n/a'); // "n/a"
asString()accepts only scalar values — arrays and objects fall back to$default. Non-string scalars are cast first (123→"123").
Signatures (same shape for every method):
Validate::asString(mixed $data, mixed $default = null): mixed
// asInteger / asFloat / asBoolean likewise
IP, URL and Email
Validate::asIp('1.2.3.4'); // "1.2.3.4"
Validate::asIp('nope', 'unknown'); // "unknown"
Validate::asUrl('https://example.id'); // sanitized URL
Validate::asUrl('', 'none'); // "none"
Validate::asEmail('me@example.id'); // "me@example.id"
Validate::asEmail('not-an-email'); // null (the default)
asUrl()sanitizes rather than strictly validates — for security checks, validate the URL's host/scheme yourself after sanitizing.
Signatures:
Validate::asIp(mixed $data, mixed $default = null): mixed
Validate::asUrl(mixed $data, mixed $default = null): mixed
Validate::asEmail(mixed $data, mixed $default = null): mixed
Validate Quick Reference
| Method | Purpose | Returns |
|---|---|---|
Validate::asArray($data,$default) |
Value as array | mixed |
Validate::asObject($data,$default) |
Value as object | mixed |
Validate::asJson($data,$default) |
Value as JSON | mixed |
Validate::asString($data,$default) |
Tags stripped, quotes kept | mixed |
Validate::asInteger($data,$default) |
Valid int or default | mixed |
Validate::asFloat($data,$default) |
Valid float or default | mixed |
Validate::asBoolean($data,$default) |
Bool or default | mixed |
Validate::asIp($data,$default) |
Valid IP or default | mixed |
Validate::asUrl($data,$default) |
Sanitized URL or default | mixed |
Validate::asEmail($data,$default) |
Valid email or default | mixed |
Related source: System/Libraries/Validate.php.