# Phlo Manual

Auto-generated reference of every built-in object and function in the Phlo runtime. Source: `/srv/control/phlo/resources/` plus core `/srv/control/phlo/phlo.php`.

## Core

### %cookies

Cookies data object

- File: `resources/cookies.phlo`
- `cookies->controller` (line 9)
- `cookies->lifetimeDays` (line 11)
- `cookies->objSet($key, $value, array $options = [])` (line 13)
- `cookies->__unset($key)` (line 21)

### %lang

Language and translation resource

- File: `resources/lang.phlo`
- `function nl($text, ...$args)` (line 11)
- `function en($text, ...$args)` (line 12)
- `lang::asyncBatch($from, $to, $json)` (line 14)
- `lang->view` (line 21)
- `lang->model` (line 23)
- `lang::fileCache` (line 24)
- `lang->file($lang)` (line 26)
- `lang->escape($value)` (line 28)
- `lang->unescape($value)` (line 29)
- `lang->lineValue($line, $eq)` (line 31)
- `lang->readAll($file)` (line 37)
- `lang->search($file, $hash)` (line 48)
- `lang->lookup($hash)` (line 94)
- `lang->save($lang, $pairs)` (line 105)
- `lang->transContext` (line 119)
- `lang->browser` (line 121)
- `lang->cookie` (line 122)
- `lang->detect($text, $fallback = 'en')` (line 123)
- `lang->hash($from, $text)` (line 132)
- `lang->translation($from, $text, ...$args)` (line 133)
- `lang->translate($from, $to, $text)` (line 152)
- `lang->translateBatch($from, $to, $texts)` (line 161)

### %payload

POST, PUT, PATCH and file-upload data object

- File: `resources/payload.phlo`
- `payload->controller` (line 10)

### %session

Session data object

- File: `resources/session.phlo`
- `session->controller` (line 9)
- `session->__set($key, $value)` (line 12)
- `session->__unset($key)` (line 13)
- `session->__isset($key)` (line 14)
- `session->objRegenerateId($deleteOld = true)` (line 16)

### %sitemap

Generic multilingual sitemap generator

- File: `resources/sitemap.phlo`
- `route GET sitemap.xml` (line 10)
- `sitemap->intl($uri)` (line 12)
- `sitemap->view` (line 14)
- `sitemap->page($uri)` (line 22)
- `sitemap->xlink($lang, $uri)` (line 33)
- `sitemap->link($lang, $uri)` (line 34)

### %tasks

Cron runner for %app->tasks. One cron entry per app triggers this every minute.

- File: `resources/tasks.phlo`
- `tasks::dir` (line 9)
- `tasks::run` (line 11)
- `tasks::saveRun($name, $do, $schedule, $return)` (line 26)
- `tasks::due($name, $task, $now)` (line 28)
- `tasks::fire($do)` (line 46)
- `tasks::lastRun($name)` (line 56)
- `tasks::markRun($name, $ts)` (line 61)
- `tasks::lock($name)` (line 63)
- `tasks::unlock($name)` (line 70)

### %useragent

User agent information

- File: `resources/useragent.phlo`
- `useragent->source` (line 9)
- `useragent->os` (line 11)
- `useragent->osV` (line 27)
- `useragent->osFull` (line 38)
- `useragent->name` (line 47)
- `useragent->version` (line 64)
- `useragent->full` (line 75)
- `useragent->device` (line 84)

### %visitors

Visitor tracking via heartbeat

- File: `resources/visitors.phlo`
- `visitors::table` (line 11)
- `visitors::columns` (line 12)
- `visitors::history` (line 14)
- `visitors::online` (line 15)
- `visitors::lastHour` (line 16)
- `visitors::isBot(?string $ua):bool` (line 18)
- `visitors::parseReferrer(string $url):string` (line 23)
- `route PUT heartbeat` (line 30)

### %websocket

Server-side WebSocket handler via PhloWS

- File: `resources/websocket.phlo`
- `websocket::connect($host, $token, $socket)` (line 10)
- `websocket::auth($host, $token, $socket)` (line 11)
- `websocket::receive($host, $token, $socket, $data)` (line 12)
- `websocket::close($host, $token, $socket)` (line 13)

### %WhatsApp

WhatsApp client for PhloWA using whatsapp-web.js

- File: `resources/WhatsApp.phlo`
- `WhatsApp->__construct(public string $url, public string $secret)` (line 10)
- `WhatsApp::channel($channel)` (line 12)
- `WhatsApp->number($contact)` (line 14)
- `WhatsApp->isGroup($contact)` (line 15)
- `WhatsApp->status` (line 17)
- `WhatsApp->health` (line 18)
- `WhatsApp->qr` (line 19)
- `WhatsApp->disconnect` (line 20)
- `WhatsApp->read($chat)` (line 22)
- `WhatsApp->reaction($msg, $emoji)` (line 23)
- `WhatsApp->text($to, $text)` (line 25)
- `WhatsApp->image($to, file $file, $text = void)` (line 26)
- `WhatsApp->location($to, $lat, $lon, $text)` (line 27)
- `WhatsApp->document($to, file $file, $text = void)` (line 28)
- `WhatsApp->audio($to, file $file)` (line 30)
- `WhatsApp->voice($to, file $file)` (line 31)
- `WhatsApp->poll($to, $name, array $options, bool $multi = false)` (line 33)
- `WhatsApp->startTyping($to)` (line 35)
- `WhatsApp->stopTyping($to)` (line 36)
- `WhatsApp->request($action, ...$data)` (line 38)

### Functions

- `active(bool $cond, string $classList = void)`
- `age(int $time)`
- `age_human(int $age)`
- `apcu($key, $cb, int $duration = 3600, bool $log = true)`
- `await(...$jobs)`
- `button(...$args):string`
- `camel(string $text)`
- `chunk(...$cmds):void`
- `create(iterable $items, \Closure $keyCb, ?\Closure $valueCb = null)`
- `en($text, ...$args)`
- `exec_stream(string $cmd, ?int $timeoutSec = 0)`
- `HTTP(string $url, array $headers = [], bool $JSON = false, $POST = null, $PUT = null, $PATCH = null, bool $DELETE = false, ?string $agent = null)`
- `input(...$args):string`
- `n8n($webhook, ?array $data = null, $test = false)`
- `n8n_test($webhook, ?array $data = null)`
- `nl($text, ...$args)`
- `notify(string $title, string $body = '', string $type = 'info', string $level = 'info', ?string $user = null):void`
- `phlo(?string $phloName = null, ...$args):mixed`
- `phlo_app(...$args):void`
- `phlo_async(string $cb, ...$args)`
- `phlo_cli(array $args):void`
- `phlo_exception(Throwable $e):void`
- `phlo_exists(string $obj)`
- `phlo_load(bool $http):void`
- `phlo_stream(string $cb, ...$args)`
- `phlo_sync(string $cb, ...$args)`
- `phlo_thread():void`
- `select(...$args):string`
- `slug(string $text)`
- `tag(string $tagName, ?string $inner = null, ...$args)`
- `textarea(...$args):string`
- `time_human(?int $time = null)`
- `wsCast($wsTarget = 'all', $wsHost = host, $wsPort = websocket, ...$data)`

## AI

### %AI

Unified AI facade with engine auto-detect

- File: `resources/AI/AI.phlo`
- `AI::engines` (line 10)
- `AI::sseDecodeEvents(string &$buffer, string $chunk):array` (line 11)
- `AI::sseStreamJSONWithTool(string $url, array $headers, array $payload, \Closure $extractText, \Closure $extractTool, ?\Closure $cb = null, ?\Closure $toolCb = null):obj` (line 31)
- `AI::http(string $url, array $headers, bool $json = true, mixed $post = null):string` (line 62)
- `AI::resolve(...$args):array` (line 75)
- `AI->chat(...$args)` (line 83)
- `AI->stream(...$args):Generator` (line 87)
- `AI->stream_with_tool(...$args):obj` (line 91)
- `AI->embedding(...$args)` (line 95)
- `AI->vision(...$args)` (line 99)
- `AI->transcribe(...$args)` (line 103)

### %Claude

Anthropic Claude API

- File: `resources/AI/Claude.phlo`
- `Claude::model` (line 10)
- `Claude::context(...$args)` (line 12)
- `Claude::tool($tool):array` (line 22)
- `Claude->embedding($input, $model = 'text-embedding-3-small')` (line 32)
- `Claude->vision($text, $image, $stream = false, ...$args)` (line 34)
- `Claude->chat(...$args)` (line 41)
- `Claude->parseSSE(string $url, array $headers, array $payload):Generator` (line 58)
- `Claude->stream(...$args):Generator` (line 90)
- `Claude->request($uri, ...$args)` (line 103)

### %DeepSeek

DeepSeek API

- File: `resources/AI/DeepSeek.phlo`
- `DeepSeek::model` (line 10)
- `DeepSeek::context(...$args)` (line 12)
- `DeepSeek::tool($tool):array` (line 20)
- `DeepSeek->embedding($input, $model = 'text-embedding-3-small')` (line 35)
- `DeepSeek->chat(...$args)` (line 37)
- `DeepSeek->parseSSE(string $url, array $headers, array $payload):Generator` (line 46)
- `DeepSeek->stream(...$args):Generator` (line 77)
- `DeepSeek->request($uri, $JSON = true, ...$args)` (line 86)

### %Gemini

Google Gemini API

- File: `resources/AI/Gemini.phlo`
- `Gemini::model` (line 10)
- `Gemini::endpoint` (line 11)
- `Gemini::context(...$args)` (line 13)
- `Gemini::tool($tool):array` (line 24)
- `Gemini->embedding($input, $model = 'text-embedding-004')` (line 34)
- `Gemini->vision($text, $image, $stream = false, ...$args)` (line 36)
- `Gemini->chat(...$args)` (line 44)
- `Gemini->parseSSE(string $url, array $headers, array $payload):Generator` (line 59)
- `Gemini->stream(...$args):Generator` (line 90)
- `Gemini->request($path, ...$args)` (line 98)

### %OpenAI

Basic OpenAI functions

- File: `resources/AI/OpenAI.phlo`
- `OpenAI::model` (line 10)
- `OpenAI::voices` (line 11)
- `OpenAI::context(...$args):array` (line 12)
- `OpenAI::tool($tool):array` (line 19)
- `OpenAI->chat(...$args):obj` (line 33)
- `OpenAI->embedding($input, $model = 'text-embedding-3-small')` (line 43)
- `OpenAI->parseSSE(string $url, array $headers, array $payload):Generator` (line 44)
- `OpenAI->stream(...$args):Generator` (line 75)
- `OpenAI->transcribe($file, $model = 'whisper-1', ...$args):obj` (line 84)
- `OpenAI->vision($text, $image, $stream = false, ...$args):obj` (line 95)
- `OpenAI->request($uri, $JSON = true, $token = null, ...$args)` (line 101)

### Functions

- `answer($question, ...$options)`

## DB

### %DB

Database engine class

- File: `resources/DB/DB.phlo`
- `DB->PDO` (line 11)
- `DB->fieldQuotes` (line 12)
- `DB->load(string $table, string $columns = '*', string $where = void, string $joins = void, string $group = void, string $limit = void, string $order = void, ...$args)` (line 14)
- `DB->query($query, ...$args)` (line 26)
- `DB->column(...$args)` (line 45)
- `DB->item(...$args)` (line 46)
- `DB->pair(...$args)` (line 47)
- `DB->group(...$args)` (line 48)
- `DB->records(...$args)` (line 49)
- `DB->rows(...$args)` (line 50)
- `DB->record(...$args)` (line 51)
- `DB->create(string $table, ...$data)` (line 53)
- `DB->change(string $table, string $where, ...$data)` (line 62)
- `DB->delete(string $table, string $where, ...$args)` (line 72)
- `DB->begin` (line 73)
- `DB->commit` (line 74)
- `DB->rollback` (line 75)
- `DB->transaction($callback)` (line 77)

### %JSONDB

JSON file database driver. One JSONDB instance = one JSON file = one model table. No joins, no transactions, no schema introspection.

- File: `resources/DB/JSONDB.phlo`
- `JSONDB::__handle` (line 11)
- `JSONDB->__construct(private string $file)` (line 12)
- `JSONDB->PDO` (line 16)
- `JSONDB->fieldQuotes` (line 17)
- `JSONDB->lastInsertedId` (line 18)
- `JSONDB->objRead` (line 20)
- `JSONDB->objWrite(array $data)` (line 21)
- `JSONDB->objNextId(array $data)` (line 22)
- `JSONDB->objFilter(array $data, string $where = void, ...$args)` (line 24)
- `JSONDB->objSelect(string $where = void, string $limit = void, string $order = void, ...$args)` (line 48)
- `JSONDB->create(string $table, ...$data)` (line 59)
- `JSONDB->change(string $table, string $where, ...$data)` (line 73)
- `JSONDB->delete(string $table, string $where, ...$args)` (line 90)
- `JSONDB->load(string $table, string $columns = '*', string $where = void, string $joins = void, string $group = void, string $limit = void, string $order = void, ...$args)` (line 99)
- `JSONDB->query($query, ...$args)` (line 104)
- `JSONDB->begin` (line 106)
- `JSONDB->commit` (line 107)
- `JSONDB->rollback` (line 108)

### %JSON_result

Minimal PDOStatement-like wrapper for JSONDB result arrays

- File: `resources/DB/JSON.result.phlo`
- `JSON_result::__handle` (line 9)
- `JSON_result->data` (line 10)
- `JSON_result->__construct(array $data)` (line 11)
- `JSON_result->fetchAll($mode = 2)` (line 13)
- `JSON_result->fetchObject($class = 'obj')` (line 44)
- `JSON_result->fetch($mode = 2)` (line 52)
- `JSON_result->fetchColumn($col = 0)` (line 59)
- `JSON_result->rowCount` (line 66)

### %migrate

Database migration runner

- File: `resources/DB/migrate.phlo`
- `migrate::setup($db = null)` (line 10)
- `migrate::applied($db = null)` (line 15)
- `migrate::run(string $path, $db = null)` (line 20)
- `migrate::rollback($db = null)` (line 39)

### %model

Phlo ORM class with unified columns and schema

- File: `resources/DB/model.phlo`
- `model::DB` (line 11)
- `model::objRecords` (line 12)
- `model::objLoaded` (line 13)
- `model::objCache` (line 14)
- `model::objRecordLimit` (line 15)
- `model::objSoftDelete` (line 16)
- `model::objAudit` (line 17)
- `model::objValidate` (line 18)
- `model::objLastErrors` (line 19)
- `model::idColumn` (line 20)
- `model::idType` (line 21)
- `model::canView` (line 23)
- `model::canCreate` (line 24)
- `model::canChange` (line 25)
- `model::canDelete` (line 26)
- `model::state` (line 28)
- `model::columns` (line 29)
- `model::_columns` (line 36)
- `model::fields` (line 41)
- `model::_fields` (line 46)
- `model::field($name)` (line 52)
- `model::create(...$args)` (line 54)
- `model::objRunValidation($data)` (line 68)
- `model::objErrors` (line 79)
- `model::createRecord(...$args)` (line 80)
- `model::change($where, ...$args)` (line 81)
- `model::delete($where, ...$args)` (line 83)
- `model::objLogChange($where, ...$args)` (line 99)
- `model->objSave` (line 110)
- `model::transaction($callback)` (line 134)
- `model::query` (line 135)
- `model::objIncludeDeleted` (line 137)
- `model::objWithDeleted($callback)` (line 138)
- `model::objRestore($id)` (line 148)
- `model::column(...$args)` (line 150)
- `model::item(...$args)` (line 151)
- `model::pair(...$args)` (line 152)
- `model::records(...$args)` (line 153)
- `model::recordCount(...$args)` (line 154)
- `model::record(...$args)` (line 155)
- `model::recordsLoad($args, $fetch, $fetchMode, $saveRelations = false)` (line 157)
- `model::objRel($key)` (line 182)
- `model->objState` (line 187)
- `model->objGet($key)` (line 188)
- `model->objIn($ids)` (line 189)
- `model->getParent($key)` (line 191)
- `model->getChildren($key)` (line 214)
- `model->getMany($key)` (line 234)
- `model->getCount($key)` (line 259)
- `model->getLast($key)` (line 293)
- `model::objResolveClass($name)` (line 320)
- `model::objShortName($class = null)` (line 321)
- `model::objParents` (line 323)
- `model::objChildren` (line 329)
- `model::objMany` (line 335)

### %MySQL

MySQL handler via DB class

- File: `resources/DB/MySQL.phlo`
- `MySQL->PDO` (line 11)
- `MySQL->objPers` (line 12)

### %PostgreSQL

PostgreSQL resource

- File: `resources/DB/PostgreSQL.phlo`
- `PostgreSQL->PDO` (line 11)
- `PostgreSQL->fieldQuotes` (line 12)

### %Qdrant

Embeddings resource with Qdrant

- File: `resources/DB/Qdrant.phlo`
- `Qdrant->get(string $input, ?string $model = null)` (line 10)
- `Qdrant->collections` (line 12)
- `Qdrant->create($collection, $size = 1536, $distance = 'Cosine')` (line 13)
- `Qdrant->upsert($collection, $id, $input, ...$payload)` (line 14)
- `Qdrant->delete($collection, ...$ids)` (line 15)
- `Qdrant->search($collection, $input = null, $top = 100)` (line 16)
- `Qdrant->drop($collection)` (line 17)
- `Qdrant->request($uri, ...$data)` (line 19)

### %query

Fluent query builder for Phlo ORM

- File: `resources/DB/query.phlo`
- `query->class` (line 10)
- `query->conditions` (line 11)
- `query->bindings` (line 12)
- `query->orderBy` (line 13)
- `query->limitVal` (line 14)
- `query->offsetVal` (line 15)
- `query->fq` (line 16)
- `query->q($column)` (line 17)
- `query->eq($column, $value)` (line 23)
- `query->neq($column, $value)` (line 24)
- `query->gt($column, $value)` (line 25)
- `query->gte($column, $value)` (line 26)
- `query->lt($column, $value)` (line 27)
- `query->lte($column, $value)` (line 28)
- `query->like($column, $value)` (line 29)
- `query->in($column, array $values)` (line 30)
- `query->isNull($column)` (line 31)
- `query->notNull($column)` (line 32)
- `query->between($column, $min, $max)` (line 33)
- `query->raw($sql, ...$bindings)` (line 34)
- `query->where($condition, ...$values)` (line 35)
- `query->order($order)` (line 41)
- `query->limit($limit)` (line 46)
- `query->offset($offset)` (line 51)
- `query->build` (line 55)
- `query->records` (line 63)
- `query->record` (line 64)
- `query->column` (line 65)
- `query->item` (line 66)
- `query->count` (line 67)
- `query->delete` (line 68)

### %SQLite

SQLite resource

- File: `resources/DB/SQLite.phlo`
- `SQLite::__handle` (line 11)
- `SQLite->__construct(private string $file)` (line 12)
- `SQLite->PDO` (line 13)

## DOM

### %cookiewall

Subtle GDPR cookie-consent banner (English-only). For multilingual sites: DOM/cookiewall.translated.

- File: `resources/DOM/cookiewall.phlo`
- `cookiewall::__handle` (line 10)
- `cookiewall->choice` (line 12)
- `cookiewall->hasChosen` (line 13)
- `cookiewall->canTrack` (line 14)
- `cookiewall->canAnalytics` (line 15)
- `route async POST cookiewall accept all` (line 17)
- `route async POST cookiewall accept essential` (line 22)
- `cookiewall->banner` (line 27)

### %cookiewall_translated

Multilingual cookiewall variant. {en: ...} tags resolve via Phlo's lang system. For English-only: DOM/cookiewall.

- File: `resources/DOM/cookiewall.translated.phlo`
- `cookiewall_translated->banner` (line 12)

### %CSS_fixes

Single Page App basic CSS boilerplate fixes

- File: `resources/DOM/CSS.fixes.phlo`

### %CSS_var

CSS variable proxy via app.var

- File: `resources/DOM/CSS.var.phlo`

### %datatags

Single Page App datatag plugin

- File: `resources/DOM/datatags.phlo`

### %dialog

Single Page App dialog resource

- File: `resources/DOM/dialog.phlo`

### %exists

onExist helper for dynamic SPA elements

- File: `resources/DOM/exists.phlo`

### %form

Single Page App form handler and input state saver

- File: `resources/DOM/form.phlo`

### %image_resizer

Client-side file upload image resizer

- File: `resources/DOM/image.resizer.phlo`

### %link

Single Page App async link handler

- File: `resources/DOM/link.phlo`

### %markdown

Client-side markdown parser

- File: `resources/DOM/markdown.phlo`

### %shorthands

onChange, onClick and onInput event shorthands

- File: `resources/DOM/shorthands.phlo`

### %store

Stateful binding engine

- File: `resources/DOM/store.phlo`

### %template

Single Page App client-side templating

- File: `resources/DOM/template.phlo`

### %timestamps

DOM live timestamps

- File: `resources/DOM/timestamps.phlo`

### %toasts

Simple toast resource

- File: `resources/DOM/toasts.phlo`

### %visible

onVisible and onVisibleIn helpers for DOM visibility

- File: `resources/DOM/visible.phlo`

### %websocket

Client-side WebSocket handler

- File: `resources/DOM/websocket.phlo`

## fields

### %field

Base ORM field

- File: `resources/fields/field.phlo`
- `function field($type, ...$args)` (line 10)
- `field::__handle` (line 12)
- `field->title` (line 14)
- `field->input($record)` (line 16)
- `field->label($record)` (line 17)
- `field->objColumns` (line 19)
- `field->objValidate($value)` (line 21)

### %field_bool

Boolean field

- File: `resources/fields/bool.phlo`
- `field_bool->true` (line 11)
- `field_bool->false` (line 12)
- `field_bool->label($record)` (line 14)
- `field_bool->input($record)` (line 15)
- `field_bool->parse($record)` (line 16)
- `field_bool->nullable` (line 17)
- `field_bool->objColumns` (line 19)

### %field_child

Child relation field

- File: `resources/fields/child.phlo`
- `field_child->list` (line 11)
- `field_child->change` (line 12)
- `field_child->create` (line 13)
- `field_child->record` (line 14)
- `field_child->count($record)` (line 16)
- `field_child->last($record)` (line 17)
- `field_child->label($record)` (line 18)
- `field_child->input($record)` (line 19)
- `field_child->link($record)` (line 20)

### %field_date

Date field

- File: `resources/fields/date.phlo`
- `field_date->handle` (line 11)
- `field_date->objColumns` (line 13)

### %field_datetime

Date-time field

- File: `resources/fields/datetime.phlo`
- `field_datetime->handle` (line 11)
- `field_datetime->change` (line 12)
- `field_datetime->create` (line 13)
- `field_datetime->label($record)` (line 15)
- `field_datetime->labelIconClass($value)` (line 16)
- `field_datetime->input($record)` (line 17)
- `field_datetime->parse($record)` (line 18)
- `field_datetime->objColumns` (line 24)

### %field_email

Email field

- File: `resources/fields/email.phlo`
- `field_email->label($record)` (line 12)

### %field_file

File field

- File: `resources/fields/file.phlo`
- `field_file->canDelete` (line 11)
- `field_file->delete` (line 12)
- `field_file->path` (line 13)
- `field_file->uri` (line 14)
- `field_file->length` (line 15)
- `field_file->label($record)` (line 17)
- `field_file->input($record)` (line 18)
- `field_file->parse($record)` (line 27)
- `field_file->read($record, $path = null)` (line 39)
- `field_file->write($file)` (line 45)
- `field_file->writePath($file, $path = null)` (line 46)
- `field_file->objColumns` (line 53)

### %field_image

Image field

- File: `resources/fields/image.phlo`
- `field_image->delete` (line 11)
- `field_image->uri` (line 12)
- `field_image->path` (line 13)
- `field_image->thumbPath` (line 14)
- `field_image->thumbSize` (line 15)
- `field_image->thumbUri` (line 16)
- `field_image->label($record)` (line 18)
- `field_image->input($record)` (line 19)
- `field_image->write($file)` (line 28)
- `field_image->objColumns` (line 30)

### %field_many

Many-to-many relation field

- File: `resources/fields/many.phlo`
- `field_many->list` (line 11)
- `field_many->record` (line 12)
- `field_many->create` (line 13)
- `field_many->change` (line 14)
- `field_many->count($record)` (line 16)
- `field_many->label($record)` (line 17)
- `field_many->link($record)` (line 18)
- `field_many->input($record)` (line 19)
- `field_many->objColumns` (line 21)

### %field_multiselect

Multi-select via checkboxes; slaat de keuze als CSV op in één verborgen veld (geen save-aanpassing nodig).

- File: `resources/fields/multiselect.phlo`
- `field_multiselect->label($record)` (line 11)
- `field_multiselect->input($record)` (line 13)
- `field_multiselect->objColumns` (line 20)

### %field_number

Number field

- File: `resources/fields/number.phlo`
- `field_number->decimals` (line 11)
- `field_number->length` (line 12)
- `field_number->min` (line 13)
- `field_number->label($record)` (line 15)
- `field_number->input($record)` (line 16)
- `field_number->objColumns` (line 18)

### %field_parent

Parent relation field

- File: `resources/fields/parent.phlo`
- `field_parent->label($record)` (line 11)
- `field_parent->input($record)` (line 12)
- `field_parent->link($record, $content = null)` (line 13)
- `field_parent->options` (line 14)
- `field_parent->objColumns` (line 16)

### %field_password

Password field

- File: `resources/fields/password.phlo`
- `field_password->list` (line 11)
- `field_password->required` (line 12)
- `field_password->minlength` (line 13)
- `field_password->placeholder` (line 14)
- `field_password->input($record)` (line 16)
- `field_password->label($record)` (line 17)
- `field_password->parse($record)` (line 18)
- `field_password->objColumns` (line 20)

### %field_price

Price field

- File: `resources/fields/price.phlo`
- `field_price->decimals` (line 11)

### %field_select

Select field

- File: `resources/fields/select.phlo`
- `field_select->input($record)` (line 11)
- `field_select->objColumns` (line 13)

### %field_text

Text field

- File: `resources/fields/text.phlo`
- `field_text->length` (line 11)
- `field_text->multiline` (line 12)
- `field_text->label($record)` (line 14)
- `field_text->input($record)` (line 15)
- `field_text->inputField($record)` (line 16)
- `field_text->inputMulti($record)` (line 17)
- `field_text->objColumns` (line 19)

### %field_token

Token field

- File: `resources/fields/token.phlo`
- `field_token->length` (line 11)
- `field_token->default` (line 12)
- `field_token->create` (line 13)
- `field_token->change` (line 14)
- `field_token->search` (line 15)
- `field_token->label($record)` (line 17)
- `field_token->parse($record)` (line 18)
- `field_token->objColumns` (line 20)

### %field_virtual

Virtual field

- File: `resources/fields/virtual.phlo`
- `field_virtual->create` (line 11)
- `field_virtual->change` (line 12)
- `field_virtual->objColumns` (line 14)

### %field_wysiwyg

WYSIWYG field

- File: `resources/fields/wysiwyg.phlo`
- `field_wysiwyg->input($record)` (line 11)
- `field_wysiwyg->objColumns` (line 19)

### Functions

- `field($type, ...$args)`

## files

### %CSV

CSV reader resource

- File: `resources/files/CSV.phlo`
- `CSV::__handle` (line 9)
- `CSV->__construct(string $filename, ?string $path = null)` (line 10)
- `CSV->objFile:string` (line 16)
- `CSV->objRead` (line 18)

### %DOCX

DOCX reader resource

- File: `resources/files/DOCX.phlo`
- `DOCX->__construct(string $file)` (line 10)
- `DOCX::toText(string $file):string` (line 23)

### %file

File resource

- File: `resources/files/file.phlo`
- `file::__handle` (line 9)
- `file->__construct(public string $file, ?string $name = null, $contents = null, ...$args)` (line 10)
- `file->append(string $data)` (line 16)
- `file->basename` (line 17)
- `file->base64` (line 18)
- `file->contents` (line 19)
- `file->contentsINI(bool $parse = true)` (line 20)
- `file->contentsJSON($assoc = null)` (line 21)
- `file->copy($to)` (line 22)
- `file->created` (line 23)
- `file->createdAge` (line 24)
- `file->createdHuman` (line 25)
- `file->curl($type = null, $filename = null)` (line 26)
- `file->delete` (line 27)
- `file->exists` (line 28)
- `file->ext` (line 29)
- `file->filename` (line 30)
- `file->getLine` (line 31)
- `file->getLength(int $length)` (line 32)
- `file->is(string $file)` (line 33)
- `file->md5` (line 34)
- `file->mime` (line 35)
- `file->modified` (line 36)
- `file->modifiedAge` (line 37)
- `file->modifiedHuman` (line 38)
- `file->move($to)` (line 39)
- `file->name` (line 40)
- `file->output($download = false)` (line 41)
- `file->path` (line 42)
- `file->pathRel` (line 43)
- `file->pointer` (line 44)
- `file->readable` (line 45)
- `file->src` (line 46)
- `file->size` (line 47)
- `file->sizeHuman(int $precision = 0)` (line 48)
- `file->sha1` (line 49)
- `file->shortenTo(int $length)` (line 50)
- `file->title` (line 51)
- `file->token($length = 20)` (line 52)
- `file->type` (line 53)
- `file->touch` (line 54)
- `file->writable` (line 55)
- `file->writeINI($data, bool $deleteEmpty = false)` (line 56)
- `file->writeJSON($data, bool $deleteEmpty = false)` (line 57)
- `file->writeJSONplain($data, bool $deleteEmpty = false)` (line 58)
- `file->write(string $data, bool $deleteEmpty = false)` (line 59)
- `file->objInfo` (line 66)

### %img

GD image resource

- File: `resources/files/img.phlo`
- `img::detect($data)` (line 9)
- `img::search($search)` (line 19)
- `img::__handle` (line 31)
- `img->__construct(public string $file)` (line 32)
- `img->src:GdImage` (line 34)
- `img->width` (line 35)
- `img->height` (line 36)
- `img->scale($width = null, $height = null, $crop = false)` (line 38)
- `img->ext($file = null)` (line 69)
- `img->source($format = null)` (line 71)
- `img->save($file = null)` (line 77)
- `img->write($format = null, $file = null)` (line 82)

### %INI

Generic INI resource

- File: `resources/files/INI.phlo`
- `INI->objFile:string` (line 9)
- `INI::__handle` (line 11)
- `INI->__construct(string $filename, ?string $path = null, bool $parse = true)` (line 12)
- `INI->objRead($parse = true)` (line 18)
- `INI->objWrite` (line 19)
- `INI->__destruct` (line 21)

### %JSON

Generic JSON resource

- File: `resources/files/JSON.phlo`
- `JSON::__handle` (line 10)
- `JSON->__construct(string $filename, ?string $path = null, $assoc = null)` (line 11)
- `JSON->objFile:string` (line 17)
- `JSON->objTouch` (line 19)
- `JSON->objRead($assoc = null)` (line 20)
- `JSON->objWrite($data, $flags = null)` (line 21)
- `JSON->__destruct` (line 23)

### %PDF

PDF generator and reader

- File: `resources/files/PDF.phlo`
- `PDF::toText(string $file):string` (line 9)
- `PDF->title` (line 21)
- `PDF->author` (line 22)
- `PDF->subject` (line 23)
- `PDF->keywords` (line 24)
- `PDF->creator` (line 25)
- `PDF->filename` (line 27)
- `PDF->mode` (line 28)
- `PDF->fromHTML($HTML)` (line 30)

### %XLSX

XLSX reader resource

- File: `resources/files/XLSX.phlo`
- `XLSX->__construct(string $file)` (line 10)

## security

### %audit

Audit log for model mutations (opt-in via static idColumn/objAudit). Schema: resources/security/audit.sql

- File: `resources/security/audit.phlo`
- `audit->log($model, $action, $before = [], $after = [], $exclude = [])` (line 10)
- `audit->diff($before, $after)` (line 31)
- `audit->history($model, $recordId, $limit = 50)` (line 40)
- `audit->byUser($userId, $fromTs = 0, $limit = 100)` (line 48)
- `audit->purge($olderThanSeconds = 31536000)` (line 55)

### %creds

Credentials resolver from env and ini sources

- File: `resources/security/creds.phlo`
- `creds->__construct(?array $values = null)` (line 9)
- `creds->resolve` (line 16)
- `creds->loadINI(string $file):array` (line 24)
- `creds->envValues(bool $hostScoped = false):array` (line 30)
- `creds->hostKey` (line 49)
- `creds->envAssign(array &$target, array $parts, string $value):void` (line 55)
- `creds->merge(array &$base, array $add):void` (line 70)
- `creds->objGet($key)` (line 80)
- `creds->objInfo` (line 85)

### %CSRF

Rotating async CSRF protection for Phlo requests

- File: `resources/security/CSRF.phlo`
- `CSRF->view` (line 11)
- `CSRF->token` (line 12)
- `CSRF->verify` (line 13)
- `CSRF->update` (line 14)

### %JWT

Sign and verify compact HS256 JSON Web Tokens (RFC 7519), secure by default

- File: `resources/security/JWT.phlo`
- `JWT->__construct(public string $secret, public string $issuer = void, public int $leeway = 30)` (line 10)
- `JWT->sign(array $claims, int $ttl = 3600):string` (line 14)
- `JWT->verify(string $token):array` (line 23)
- `JWT->sig(string $body):string` (line 39)
- `JWT->encode($data):string` (line 40)
- `JWT->decode(string $data):string` (line 41)

### %rate

Rate-limit (fixed window) op rate_limit-tabel. Schema: resources/security/rate.sql

- File: `resources/security/rate.phlo`
- `rate->check($key, $limit, $windowSeconds, $storage = 'db')` (line 10)
- `rate->checkApcu($key, $limit, $windowSeconds)` (line 23)
- `rate->status($key, $limit, $windowSeconds)` (line 31)
- `rate->reset($key)` (line 38)
- `rate->purge($olderThanSeconds = 604800)` (line 39)

### %security

Generic security resource

- File: `resources/security/security.phlo`
- `security->whitelist` (line 10)
- `security->setNonce` (line 12)
- `security->frameProtect($mode = 'DENY')` (line 14)
- `security->frameWhitelist` (line 15)
- `security->strict` (line 17)
- `security->basic` (line 24)
- `security->marketing` (line 29)
- `security->api` (line 34)
- `security->base` (line 40)

### Functions

- `decrypt($encrypted, $key):string|false`
- `encrypt($data, $key):string`
- `token(int $length = 8, ?string $input = null)`

