Core
object
%cookies
/phlo/resources/cookies.phlo
method
%cookies -> controller
line 9
Deze controller haalt de huidige staat van cookies op en wijst deze toe aan de objData-eigenschap.
this->objData = $_COOKIEprop
%cookies -> lifetimeDays
line 11
Stelt de levensduur van cookies in dagen in.
180method
%cookies -> objSet ($key, $value, array $options = [])
line 13
Stelt een cookie in met de opgegeven sleutel en waarde, samen met optionele parameters voor vervaldatum, pad, beveiliging en SameSite-attributen.
$this->objData[$key] = $value
$_COOKIE[$key] = $value
$defaults = ['expires' => time() + $this->lifetimeDays * 86400, 'path' => slash, 'secure' => %req->secure, 'httponly' => true, 'samesite' => 'Lax']
setcookie($key, $value, array_merge($defaults, $options))
return truemethod
%cookies -> __unset ($key)
line 21
Verwijdert een cookie door deze uit de lokale objectgegevens en de globale $_COOKIE-array te verwijderen, en stelt de vervaldatum in op het verleden.
unset($this->objData[$key], $_COOKIE[$key])
$options = ['expires' => time() - 86400, 'path' => slash, 'secure' => %req->secure, 'httponly' => true, 'samesite' => 'Lax']
setcookie($key, void, $options)object
%lang
/phlo/resources/lang.phlo
function
function nl ($text, ...$args)
line 11
Vertaal de gegeven tekst naar het Nederlands met de opgegeven argumenten voor opmaak.
%lang->translation('nl', $text, ...$args)function
function en ($text, ...$args)
line 12
Deze functie haalt een vertaling op voor de opgegeven tekst in het Engels, en kan optioneel worden opgemaakt met extra argumenten.
%lang->translation('en', $text, ...$args)static
lang :: asyncBatch ($from, $to, $json)
line 14
Voert een batchvertaling asynchroon uit, decodeert JSON-invoer en slaat de vertalingen op als deze succesvol zijn.
%app->lang = $to
$texts = json_decode($json, true)
$translations = $this->translateBatch($from, $to, $texts)
if ($translations) $this->save($to, $translations)view
%lang -> view
line 21
Deze functie haalt de huidige taalinstelling van de applicatie op, waardoor lokalisatie van views mogelijk is.
%app->langprop
%lang -> model
line 23
Deze functie haalt het model op dat is gekoppeld aan de opgegeven taalidentificator.
'gpt-4o-mini'static
lang :: fileCache
line 24
lang::$fileCache is een statische eigenschap die gecachete taaldocumenten opslaat voor efficiënte toegang tijdens runtime.
[]method
%lang -> file ($lang)
line 26
Haal het configuratiebestand op voor de opgegeven taal, met het formaat 'langs.$lang.ini'.
langs.$lang.'.ini'method
%lang -> escape ($value)
line 28
Escaped speciale tekens in een string voor veilige uitvoer in HTML, vervangend backslashes, dubbele aanhalingstekens en regeleinden met hun respectieve escape-sequenties.
strtr((string)$value, [bs => bs.bs, dq => bs.dq, lf => '\n'])method
%lang -> unescape ($value)
line 29
Deze functie ontsnapt een gegeven string door escape-sequenties te vervangen door hun overeenkomstige karakters.
strtr(strtr($value, [bs.bs => "\x01", bs.dq => dq, '\n' => lf]), ["\x01" => bs])method
%lang -> lineValue ($line, $eq)
line 31
Extraheert en verwerkt een lijnwaarde uit een gegeven string, verwijdert omringende aanhalingstekens indien aanwezig en ontsnapt speciale tekens.
$value = rtrim(substr($line, $eq + 3), cr.lf)
if (strlen($value) > 1 && $value[0] === dq && substr($value, -1) === dq) $value = substr($value, 1, -1)
return $this->unescape($value)method
%lang -> readAll ($file)
line 37
Leest alle sleutel-waarde paren uit een opgegeven bestand en retourneert deze als een associatieve array. Als het bestand niet bestaat of geen geldig bestand is, retourneert het een lege array.
$items = []
if (!is_file($file)) return $items
foreach (file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [] AS $line){
$eq = strpos($line, ' = ')
if ($eq === false) continue
$items[substr($line, 0, $eq)] = $this->lineValue($line, $eq)
}
return $itemsmethod
%lang -> search ($file, $hash)
line 48
Zoekt naar een specifieke hash in een bestand en retourneert de bijbehorende waarde als deze is gevonden.
$size = (int)@filesize($file)
if (!$size) return null
$h = @fopen($file, 'rb')
if (!$h) return null
$lo = 0
$hi = $size
while ($hi - $lo > 4096){
$mid = intdiv($lo + $hi, 2)
fseek($h, $mid)
fgets($h)
$pos = ftell($h)
if ($pos >= $hi){
$hi = $mid
continue
}
$line = (string)fgets($h)
$eq = strpos($line, ' = ')
if ($eq === false){
$hi = $mid
continue
}
$cmp = strcmp(substr($line, 0, $eq), $hash)
if ($cmp < 0) $lo = ftell($h)
elseif ($cmp > 0) $hi = $pos
else {
fclose($h)
return $this->lineValue($line, $eq)
}
}
fseek($h, $lo)
$value = null
while (ftell($h) < $hi && ($line = fgets($h)) !== false){
$eq = strpos($line, ' = ')
if ($eq === false) continue
$cmp = strcmp(substr($line, 0, $eq), $hash)
if ($cmp > 0) break
if ($cmp === 0){
$value = $this->lineValue($line, $eq)
break
}
}
fclose($h)
return $valuemethod
%lang -> lookup ($hash)
line 94
Zoekt een waarde in de taalbestanden cache op basis van de opgegeven hash en werkt de cache bij als het bestand is gewijzigd.
$file = $this->file(%app->lang)
$mtime = (int)@filemtime($file)
$cache =& static::$fileCache[$file]
if (!$cache || $cache['mtime'] !== $mtime) $cache = ['mtime' => $mtime, 'items' => []]
if (array_key_exists($hash, $cache['items'])) return $cache['items'][$hash]
$value = $this->search($file, $hash)
if ($value === null && $mtime) $value = $this->readAll($file)[$hash] ?? null
return $cache['items'][$hash] = $valuemethod
%lang -> save ($lang, $pairs)
line 105
Slaat een set van sleutel-waardeparen op in een taaldocument, waarbij de sleutels worden gesorteerd en de bestandsrechten correct worden ingesteld.
$file = $this->file($lang)
$items = $this->readAll($file)
foreach ($pairs AS $hash => $value) $items[$hash] = $value
ksort($items, SORT_STRING)
$out = void
foreach ($items AS $hash => $value) $out .= $hash.' = '.dq.$this->escape($value).dq.lf
$tmp = $file.'.'.getmypid().'.tmp'
file_put_contents($tmp, $out, LOCK_EX)
@chmod($tmp, 0664)
rename($tmp, $file)
unset(static::$fileCache[$file])method
%lang -> transContext
line 119
Haal de vertaalcontext op van de app-auteur, die informatie geeft over het doel en het domein als deze beschikbaar is.
($instr = trim((string)(%app->transInstr ?? void))) !== void ? lf.'Context from the app author about purpose and domain: '.$instr : voidprop
%lang -> browser
line 121
Haal de voorkeurstaal uit de 'Accept-Language' HTTP-header, en retourneer de eerste overeenkomende taalcodes uit de ondersteunde talen van de applicatie.
last($langs = array_filter(explode(comma, %req->acceptLanguage), fn($lang) => isset(%app->langs[substr($lang, 0, 2)])), $langs ? substr(current($langs), 0, 2) : null)method
%lang -> cookie
line 122
Haal de taalvoorkeur uit cookies en controleer of het een geldige optie is in de beschikbare talen van de applicatie, waarbij de taal wordt geretourneerd als deze geldig is of null anders.
($lang = %cookies->lang) && %app->langs[$lang] ? $lang : nullmethod
%lang -> detect ($text, $fallback = 'en')
line 123
Detecteert de taal van de gegeven tekst en retourneert de ISO 639-1 code, met 'en' als standaard als de detectie mislukt.
$res = %OpenAI->chat (
model: $this->model,
system: 'Analyse which language this text is in and return only the ISO 639-1 code of the language, no other data!',
user: $text.lf.lf.'The ISO 639-1 code of the language is: ',
temperature: 0,
)->answer
return strlen($res) === 2 ? strtolower($res) : $fallbackmethod
%lang -> hash ($from, $text)
line 132
Genereert een hash op basis van de opgegeven tekst en een voorvoegsel van de opgegeven taal.
$from.($short = substr(implode(regex_all('/[A-Za-z0-9]+/', ucwords($text))[0]), 0, 8)).substr(md5($text), 0, 10 - strlen($short))method
%lang -> translation ($from, $text, ...$args)
line 133
Vertaling van de gegeven tekst van een opgegeven taal naar de huidige taal van de applicatie, waarbij ontbrekende vertalingen asynchroon worden afgehandeld.
if ($from === %app->lang) $translation = strtr($text, ['\n' => lf])
else {
$translation = []
$missing = []
foreach (explode(lf, $text) AS $line){
if (trim($line)){
$hash = $this->hash($from, $line)
$item = $this->lookup($hash)
if ($item === null) [$missing[$hash] = $item = $line, debug(%app->lang.': '.(strlen($line) > 20 ? substr($line, 0, 18).'...' : $line))]
}
else $item = void
$translation[] = $item
}
if ($missing) phlo_async('lang::asyncBatch', $from, %app->lang, json_encode($missing))
$translation = implode(lf, $translation)
}
return $args ? sprintf($translation, ...$args) : $translationmethod
%lang -> translate ($from, $to, $text)
line 152
Vertaal een gegeven tekst van de ene ISO 639-1 taal naar de andere met behulp van de OpenAI API, terwijl markdown-opmaak en hoofdletters behouden blijven.
if ($from === $to) return $text
return %OpenAI->chat (
model: $this->model,
system: "You will be provided with a word, sentence or (markdown) text in ISO 639-1 language $from, and your task is to translate this string into ISO 639-1 language $to. Respect markdown, missing interpunction and specific use of capitals. Give only the translation.".$this->transContext(),
user: $text,
temperature: 0,
)->answermethod
%lang -> translateBatch ($from, $to, $texts)
line 161
Vertaal een batch teksten van de ene naar de andere taal met behulp van het OpenAI chatmodel, en retourneer de vertalingen in genummerd formaat.
if ($from === $to) return $texts
$hashes = array_keys($texts)
$numbered = implode(lf, array_map(fn($i, $t) => ($i + 1).'. '.$t, array_keys($values = array_values($texts)), $values))
$answer = %OpenAI->chat (
model: $this->model,
system: "You will be provided with numbered lines in ISO 639-1 language $from. Translate each line into ISO 639-1 language $to. Return only the numbered translations in the same format. Respect markdown, missing interpunction and specific use of capitals.".$this->transContext(),
user: $numbered,
temperature: 0,
)->answer
$result = []
foreach (explode(lf, trim($answer)) AS $line){
if (preg_match('/^(\d+)\.\s*(.+)/', $line, $m))
$result[$hashes[(int)$m[1] - 1]] = $m[2]
}
return $resultobject
%payload
/phlo/resources/payload.phlo
method
%payload -> controller
line 10
Verwerkt binnenkomende verzoekpayloads op basis van het contenttype, behandelt JSON, URL-gecodeerde en multipart formuliervelden, en vult de objData-eigenschap dienovereenkomstig in.
contentType = %req->contentType
if (in_array(phlo('req')->method, ['POST', 'PUT', 'PATCH']) && str_starts_with($contentType, 'application/json')){
$data = json_read('php://input')
return $this->objData = is_object($data) ? get_object_vars($data) : (is_array($data) ? $data : [])
}
if ($_POST) $this->objImport(...$_POST)
elseif (in_array(phlo('req')->method, ['PUT', 'PATCH']) && str_starts_with($contentType, 'application/x-www-form-urlencoded')){
$body = file_get_contents('php://input')
$data = []
parse_str($body, $data)
if ($data) $this->objImport(...$data)
}
elseif (in_array(phlo('req')->method, ['PUT', 'PATCH']) && str_starts_with($contentType, 'multipart/form-data')){
$match = regex('/boundary="?([^";]+)"?/', $contentType)
if (!$match) return
$boundary = '--'.$match[1]
$arrays = []
$raw = file_get_contents('php://input')
foreach (explode($boundary, $raw) AS $part){
if (!trim($part) || $part === '--' || !str_contains($part, nl.nl)) continue
$headers = []
[$rawHeaders, $body] = explode(nl.nl, $part, 2)
foreach (explode(nl, trim($rawHeaders)) AS $header){
if (str_contains($header, colon)){
[$key, $value] = explode(colon, $header, 2)
$headers[strtolower(trim($key))] = trim($value)
}
}
if (!isset($headers['content-disposition'])) continue
if (!preg_match('/name="([^"]+)"/', $headers['content-disposition'], $match)) continue
$name = $match[1]
$body = rtrim($body, nl)
if ($body === void) $body = null
$base = $name
$keys = []
$hasEmptyIndex = false
if (preg_match('/^([^\[]+)((?:\[[^\]]*\])*)$/', $name, $m)){
$base = $m[1]
$brackets = $m[2]
if ($brackets){
preg_match_all('/\[([^\]]*)\]/', $brackets, $mm)
$keys = $mm[1]
$hasEmptyIndex = in_array(void, $keys, true)
}
}
if ($hasEmptyIndex) $arrays[] = $base
$assign = function($value) use ($base, $keys){
if ($keys){
if (!isset($this->objData[$base]) || !is_array($this->objData[$base])) $this->objData[$base] = []
$ref =& $this->objData[$base]
$count = count($keys)
foreach ($keys AS $i => $k){
$last = $i === $count - 1
if ($k === void){
if ($last) $ref[] = $value
else {
$ref[] = []
end($ref)
$idx = key($ref)
$ref =& $ref[$idx]
}
}
else {
if ($last) $ref[$k] = $value
else {
if (!isset($ref[$k]) || !is_array($ref[$k])) $ref[$k] = []
$ref =& $ref[$k]
}
}
}
}
else $this->objData[$base] = $value
};
if (preg_match('/filename="([^"]*)"/', $headers['content-disposition'], $f)){
if ($f[1] === void || $body === null){
if (!$hasEmptyIndex) $assign(null)
continue
}
$filename = $f[1]
$file = %file(tempnam(sys_get_temp_dir(), 'phlo'), $filename, $body)
$assign($file)
}
else $assign($body)
}
foreach ($this->objData AS $key => $val){
if (str_ends_with($key, '[]')){
unset($this->objData[$key])
$this->objData[substr($key, 0, -2)] = is_array($val) ? array_values(array_filter($val, fn($v) => $v !== null)) : [$val]
}
elseif (!is_array($val) && substr($key, -2) === '[]') $this->objData[$key] = [$val]
}
foreach (array_unique($arrays) AS $key) if (!isset($this->objData[$key])) $this->objData[$key] = []
}
if ($_FILES) $this->objImport(...loop($_FILES, fn($f) => is_array($f['name']) ? loop(array_keys($f['name']), fn($i) => $f['error'][$i] ? null : %file($f['tmp_name'][$i], $f['name'][$i], mime: $f['type'][$i], size: $f['size'][$i])) : ($f['error'] ? null : %file($f['tmp_name'], $f['name'], mime: $f['type'], size: $f['size']))))object
%session
/phlo/resources/session.phlo
method
%session -> controller
line 9
Initialiseert de sessie en wijst de sessiegegevens toe aan de objData-eigenschap.
ession_start()
$this->objData = $_SESSIONmethod
%session -> __set ($key, $value)
line 12
Stelt een sessievariabele in met de opgegeven sleutel op de gegeven waarde.
$_SESSION[$key] = $this->objData[$key] = $valuemethod
%session -> __unset ($key)
line 13
Verwijdert de opgegeven sleutel uit de sessiegegevens en de interne objectgegevens.
unset($this->objData[$key], $_SESSION[$key])method
%session -> __isset ($key)
line 14
Controleert of een sessievariabele die door de gegeven sleutel is geïdentificeerd, is ingesteld en niet null is.
isset($this->objData[$key])method
%session -> objRegenerateId ($deleteOld = true)
line 16
Regenerates de sessie-ID voor de huidige sessie, waarbij optioneel de oude sessiegegevens worden verwijderd op basis van de $deleteOld-parameter.
session_regenerate_id($deleteOld)
$this->objData = $_SESSIONobject
%sitemap
/phlo/resources/sitemap.phlo
route
route GET sitemap.xml
line 10
Geeft de huidige instantie van de route voor de GETSitemap-methode weer.
output($this)method
%sitemap -> intl ($uri)
line 12
Haal de geïndividualiseerde slug op voor een gegeven URI uit de slugs van de app, of retourneer de URI zelf als er geen slug wordt gevonden.
(%app->slugs ?? [])[$uri] ?? $uriview
%sitemap -> view
line 14
Genereert een XML-sitemap voor de applicatie door over de gedefinieerde pagina's te itereren en hun URL's op te nemen.
<?xml version=1.0 encoding="UTF-8"?>
<urlset xmlns=http://www.sitemaps.org/schemas/sitemap/0.9 xmlns:xhtml=http://www.w3.org/1999/xhtml xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://www.sitemaps.org/schemas/sitemap/0.9+http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd>
<foreach %app->pages AS $uri>
{{ $this->page($uri) }}
</foreach>
</urlset>view
%sitemap -> page ($uri)
line 22
Genereert een sitemap-invoer voor een specifieke weergave, inclusief gelokaliseerde URL's voor elke taal die door de applicatie wordt ondersteund.
<url>
<loc>%req->base{( $uri ?: slash )}</loc>
<foreach array_keys(%app->langs) AS $lang>
<if $lang === %app->lang>
{{ $this->xlink('x-default', $uri ?: slash) }}
</if>
{{ $this->xlink($lang, $lang === %app->lang ? ($uri ?: slash) : "/$lang".($this->intl($uri) ?: void)) }}
</foreach>
</url>view
%sitemap -> xlink ($lang, $uri)
line 33
Genereert een alternatieve link voor een sitemap-item, waarbij de taal en de basis-URI van de aanvraag worden gespecificeerd.
<xhtml:link rel=alternate hreflang="$lang" href="%req->base$uri"{{ slash }}>view
%sitemap -> link ($lang, $uri)
line 34
Genereert een linkelement voor alternatieve taalkundige versies van een pagina in de sitemap, met gebruik van de opgegeven taal en aanvraag-URI.
<link rel=alternate hreflang="$lang" href="%req->base$uri">object
%tasks
/phlo/resources/tasks.phlo
static
tasks :: dir
line 9
Toegang tot het pad van de directory voor taken, specifiek verwijzend naar 'tasks/'.
data.'tasks/'static
tasks :: run
line 11
Voert geplande taken uit door hun vervaldatum te controleren en ze te vergrendelen om gelijktijdige uitvoering te voorkomen. Het slaat de uitvoeringsdetails op en markeert de taak als voltooid na uitvoering.
is_dir(static::dir()) || mkdir(static::dir(), 0755, true)
$now = time()
foreach (%app->tasks ?? [] AS $name => $task){
$task = (object)$task
if (!static::due($name, $task, $now)) continue
if (!static::lock($name)) continue
$schedule = array_intersect_key((array)$task, array_flip(['every', 'daily', 'weekly']))
$do = is_string($task->do) ? $task->do : null
static::saveRun($name, $do, $schedule, static::fire($task->do))
static::markRun($name, $now)
static::unlock($name)
}static
tasks :: saveRun ($name, $do, $schedule, $return)
line 26
Slaat de uitvoergegevens op in een JSON-bestand in de opgegeven map, met de opgegeven naam, do, schema en return-waarden.
json_write(static::dir().$name.'.json', arr(do: $do, schedule: $schedule, return: $return))static
tasks :: due ($name, $task, $now)
line 28
Bepaalt of een geplande taak moet worden uitgevoerd op basis van de frequentie-instellingen, zoals 'elke', 'dagelijks' of 'wekelijks'. Het controleert de laatste uitvoeringstijd ten opzichte van de huidige tijd om te beslissen of de taak moet worden uitgevoerd.
$last = static::lastRun($name)
if (isset($task->every)){
$every = preg_match('/^\d/', $task->every) ? $task->every : '1 '.$task->every
$seconds = strtotime("+$every", 0) ?: 0
return $seconds > 0 && ($now - $last) >= $seconds
}
if (isset($task->daily)){
if (date('H:i', $now) !== $task->daily) return false
return $last < strtotime('today 00:00', $now)
}
if (isset($task->weekly)){
if (date('D H:i', $now) !== date('D H:i', strtotime("$task->weekly today"))) return false
return $last < strtotime('monday this week', $now)
}
return falsestatic
tasks :: fire ($do)
line 46
Voert een taak uit die is gedefinieerd door een Closure, een 'Class::method' string of een resource-naam string, en retourneert het resultaat van de uitvoering.
if ($do instanceof \Closure) return $do()
if (is_string($do) && str_contains($do, '::')){
[$class, $method] = explode('::', $do, 2)
return $class::$method()
}
if (is_string($do)) return phlo($do)
error('Task do must be Closure, "Class::method" string, or resource-name string')static
tasks :: lastRun ($name)
line 56
Haal de laatste uitvoeringstijdstempel van een taak op uit een bestand, en retourneer 0 als het bestand niet bestaat.
$file = static::dir().$name.'.last'
return is_file($file) ? (int)file_get_contents($file) : 0static
tasks :: markRun ($name, $ts)
line 61
Schrijft de tijdstempel van de laatste uitvoering van een taak naar een bestand met de naam van de taak in de opgegeven directory, met gebruik van exclusieve vergrendeling om gelijktijdige schrijfbewerkingen te voorkomen.
file_put_contents(static::dir().$name.'.last', (string)$ts, LOCK_EX)static
tasks :: lock ($name)
line 63
Maakt een lockbestand voor een taak aan als het nog niet bestaat of ouder is dan een uur.
$file = static::dir().$name.'.lock'
if (is_file($file) && (time() - filemtime($file)) < 3600) return false
touch($file)
return truestatic
tasks :: unlock ($name)
line 70
Verwijdert het vergrendelingsbestand dat aan een taak is gekoppeld, zodat deze opnieuw kan worden uitgevoerd.
@unlink(static::dir().$name.'.lock')object
%useragent
/phlo/resources/useragent.phlo
prop
%useragent -> source
line 9
Deze expressie haalt de user agent-string op uit het aanvraagobject en retourneert null als deze niet is ingesteld.
%req->userAgent ?: nullprop
%useragent -> os
line 11
Bepaalt het besturingssysteem op basis van de user agent-string door deze te vergelijken met vooraf gedefinieerde patronen.
if (!$this->source) return 'Unknown'
$list = [
'Android' => '/Android/i',
'iPadOS' => '/iPad.*OS/i',
'iOS' => '/iPhone|iPod/i',
'Windows' => '/Windows NT/i',
'macOS' => '/Mac OS X/i',
'ChromeOS' => '/CrOS/i',
'Linux' => '/Linux/i',
]
foreach ($list AS $n => $r) if (preg_match($r, $this->source)) return $n
if (preg_match('/iPad/i',$this->source) && preg_match('/Mac OS X/i',$this->source)) return 'iPadOS'
return 'Unknown'prop
%useragent -> osV
line 27
Haalt de versie van het besturingssysteem uit de user agent-string als deze beschikbaar is, en retourneert deze in een schone indeling.
if (!$this->source) return void
if (preg_match('/(?:Android|OS X|OS|Windows NT)\s*([0-9._]+)/i', $this->source, $m)){
$v = strtr($m[1], [us => dot])
$v = preg_replace('/[^0-9.].*/', void, $v)
$v = preg_replace('/(?:\.0)+$/', void, $v)
return $v
}
return voidprop
%useragent -> osFull
line 38
Deze methode retourneert de naam van het besturingssysteem samen met de versie, opgemaakt om minor versie nummers weg te laten als ze nul zijn.
if (!$this->OS) return 'Unknown'
$v = $this->osV
if (!$v) return $this->OS
$short = preg_replace('/^(\d+\.\d+).*/','$1',$v)
if (preg_match('/\.0$/',$short)) $short = preg_replace('/\.0$/', void, $short)
return trim($this->OS.' '.$short)prop
%useragent -> name
line 47
Bepaalt de naam van de webbrowser op basis van de gebruikersagentstring die in de source is opgegeven. Het controleert verschillende patronen om populaire browsers zoals Chrome, Firefox en Safari te identificeren en retourneert 'Onbekend' als er geen overeenkomst wordt gevonden.
if (!$this->source) return 'Unknown'
if (preg_match('/\bwv\b/',$this->source) || (preg_match('/Version\/\d+\.\d+/',$this->source) && strpos($this->source,'Chrome/')!==false && strpos($this->source,'Safari/')!==false && strpos($this->source,' Mobile ')!==false)) return 'Android WebView'
if (preg_match('/CriOS\/([0-9.]+)/',$this->source)) return 'Chrome'
if (preg_match('/FxiOS\/([0-9.]+)/',$this->source)) return 'Firefox'
$list = [
'Edge' => '/Edg\/([0-9.]+)/',
'Opera' => '/OPR\/([0-9.]+)/',
'Samsung Internet' => '/SamsungBrowser\/([0-9.]+)/i',
'Chrome' => '/Chrome\/([0-9.]+)/',
'Firefox' => '/Firefox\/([0-9.]+)/',
'Safari' => '/Version\/([0-9.]+).*Safari/i',
]
foreach ($list AS $n => $r) if (preg_match($r, $this->source)) return $n
return 'Unknown'prop
%useragent -> version
line 64
Haalt het versienummer uit de user agent-string als deze overeenkomt met specifieke browserpatronen, en retourneert het schoongemaakte versienummer of void als er geen overeenkomst is.
if (!$this->source) return void
if (preg_match('/(?:Edg|OPR|Chrome|Firefox|Version|CriOS|FxiOS|SamsungBrowser)\/([0-9.]+)/', $this->source, $m)){
$v = $m[1]
$v = preg_replace('/[^0-9.].*/', void, $v)
$v = preg_replace('/(?:\.0)+$/', void, $v)
return $v
}
return voidprop
%useragent -> full
line 75
Geeft de volledige user agent-string terug, inclusief de naam en versie van de user agent, geformatteerd om onnodige delen te verwijderen.
if (!$this->name) return 'Unknown'
$v = $this->version
if (!$v) return $this->name
$short = preg_replace('/^(\d+\.\d+).*/','$1',$v)
if (preg_match('/\.0$/',$short)) $short = preg_replace('/\.0$/', void, $short)
return rtrim($this->name.' '.$short)prop
%useragent -> device
line 84
Bepaalt het type apparaat (Tablet, Telefoon of Desktop) op basis van de user agent-string die is opgeslagen in de source-eigenschap.
if (!$this->source) return 'Unknown'
if (preg_match('/iPad|Tablet|Tab|SM-T|Nexus 7|Nexus 10/i', $this->source)) return 'Tablet'
if (preg_match('/Mobile|iPhone|Android.*Mobile|SM-G|Pixel [0-9]/i', $this->source)) return 'Phone'
return 'Desktop'object
%visitors
/phlo/resources/visitors.phlo
static
visitors :: table
line 11
De 'visitors::$table' verwijst naar de database tabel die is gekoppeld aan de 'visitors' resource in Phlo.
'visitors'static
visitors :: columns
line 12
Definieert de kolommen voor de 'visitors' resource, waarbij de attributen worden gespecificeerd die in de datastructuur moeten worden opgenomen.
'id,token,host,page,lang,IP,browser,os,device,requests,state,width,height,referrer,created,changed'static
visitors :: history
line 14
Haal een geschiedenis op van bezoekersaantallen, gegroepeerd op datum en tel unieke tokens en totale bezoeken.
static::records(columns: 'FROM_UNIXTIME(changed, "%Y-%m-%d") AS date,COUNT(DISTINCT token) AS visitors,COUNT(id) AS visits', group: 'date', order: 'date DESC')static
visitors :: online
line 15
Dit haalt het aantal unieke online bezoekers op die in de afgelopen 9 seconden zijn veranderd.
static::item(columns: 'COUNT(DISTINCT token)', where: 'changed >= (UNIX_TIMESTAMP() - 9)')static
visitors :: lastHour
line 16
Haal het aantal unieke bezoekers (tokens) op die in het afgelopen uur zijn veranderd.
static::item(columns: 'COUNT(DISTINCT token)', where: 'changed >= (UNIX_TIMESTAMP() - 3600)')static
visitors :: isBot (?string $ua):bool
line 18
Bepaalt of de user agent-string aangeeft dat de bezoeker een bot is door deze te vergelijken met een vooraf gedefinieerd regex-patroon.
if (!$ua) return false
return (bool)preg_match('/bot|crawl|spider|slurp|baiduspider|facebookexternalhit|twitterbot|linkedinbot|curl|wget|python-requests|go-http-client|java\//i', $ua)static
visitors :: parseReferrer (string $url):string
line 23
Analyseert de verwijzende URL om de gebruikte zoekmachine te identificeren en retourneert een geformatteerde string die de zoekmachine aangeeft of de hostnaam als er geen overeenkomst is.
static $engines = ['google' => 'Google', 'bing' => 'Bing', 'duckduckgo' => 'DuckDuckGo', 'yahoo' => 'Yahoo', 'baidu' => 'Baidu', 'yandex' => 'Yandex', 'ecosia' => 'Ecosia', 'startpage' => 'Startpage', 'brave' => 'Brave', 'kagi' => 'Kagi']
$host = strtolower(preg_replace('/^www\./', '', (string)(parse_url($url, PHP_URL_HOST) ?? '')))
foreach ($engines AS $key => $name) if (str_contains($host, $key)) return 'search:'.$name
return $host ?: substr($url, 0, 100)route
route PUT heartbeat @n,v,l,u,w,h,a,p,r,c
line 30
Deze route verwerkt PUT-verzoeken om hartslaggegevens van bezoekers vast te leggen, waarbij gebruikersconsent, apparaatinformatie en paginagegevens worden geregistreerd, terwijl unieke identificatoren en referrer-parsing worden beheerd.
if (static::isBot(%useragent->source)) return
$consent = (bool)%payload->c
$n = strlen(%payload->n) === 8 ? %payload->n : date('Ymd')
$id = $consent ? token(20, $n.space.%app->token.space.%useragent->source) : token(20, $n.space.date('Ymd').space.%app->token.space.%req->ip)
$data = arr (
token: token(20, (string)(%app->token ?? error('No app token available'))),
host: host,
page: %payload->u,
lang: strlen(%payload->l) === 2 ? %payload->l : %app->lang ?? 'en',
IP: $consent ? %req->ip : void,
browser: $consent ? %useragent->full.(%payload->a ? ' App' : void) : substr(md5((string)%useragent->source), 0, 8),
os: $consent ? %useragent->osFull : void,
device: $consent ? %useragent->device : void,
requests: %payload->p,
state: %payload->v,
width: %payload->w,
height: %payload->h,
changed: time(),
)
$record = static::record(id: $id, columns: 'id,page,referrer')
if (($referrer = %payload->r) && !$record?->referrer && !str_contains($referrer, host)) $data['referrer'] = static::parseReferrer($referrer)
if ($record) static::change('id=?', $id, ...$data)
else static::create(...$data, id: $id, created: time())view
script
line 56
Dit script beheert een heartbeat-mechanisme dat bezoekersgegevens naar de server verzendt, inclusief toestemmingsstatus en app-status, en ook het maken en bijwerken van cookies voor bezoekerstracking afhandelt.
let curpath = app.path
let heartbeatTimeout
const heartbeat = () => delay('heartbeat', 333, () => {
clearTimeout(heartbeatTimeout)
const consent = document.cookie.includes('cookieChoice=all')
if (consent){
const m = document.cookie.match(/phlo_visitor=([a-z0-9]{8})/)
if (m) window.name = m[1]
else {
window.name ||= phlo.token(8)
document.cookie = `phlo_visitor=${window.name};path=/;max-age=${365 * 86400};SameSite=Lax`
}
}
else window.name ||= phlo.token(8)
fetch('/heartbeat', {method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({n: window.name, v: app.state, l: obj('html').lang ?? 'en', u: app.path, w: innerWidth, h: innerHeight, a: app.mode, p: phlo.state.index, r: (r = document.referrer) ? (r === `${location.origin}/` ? null : r) : null, c: consent ? 1 : 0})})
heartbeatTimeout = setTimeout(heartbeat, 20000)
})
document.addEventListener('visibilitychange', heartbeat)
;['focus', 'blur', 'resize'].forEach(e => addEventListener(e, heartbeat))
app.updates.push(() => curpath !== app.path && (heartbeat(), curpath = app.path))
heartbeat()object
%websocket
/phlo/resources/websocket.phlo
static
websocket :: connect ($host, $token, $socket)
line 10
function_exists('wsConnect') && wsConnect($host, $token, $socket)static
websocket :: auth ($host, $token, $socket)
line 11
function_exists('wsAuth') && wsAuth($host, $token, $socket)static
websocket :: receive ($host, $token, $socket, $data)
line 12
function_exists('wsReceive') && wsReceive($host, $token, $socket, ...json_decode($data, true))static
websocket :: close ($host, $token, $socket)
line 13
function_exists('wsClose') && wsClose($host, $token, $socket)object%WhatsApp
/phlo/resources/WhatsApp.phlo
method
%WhatsApp -> __construct (public string $url, public string $secret)
line 10
Initialiseert een WhatsApp-instantie met een opgegeven URL en geheim, waarbij wordt gegarandeerd dat de URL eindigt met een schuine streep.
$this->url = rtrim($url, slash).slashstatic
WhatsApp :: channel ($channel)
line 12
Maakt een nieuwe instantie van het WhatsApp-kanaal met de opgegeven URL en geheim, standaard 'http://localhost:8081' en 'void' als niet gespecificeerd.
new static($channel->configData->url ?? 'http://localhost:8081', $channel->secretData->secret ?? void)method
%WhatsApp -> number ($contact)
line 14
Extraheert het telefoonnummer uit een WhatsApp-contactstring en retourneert een fout als het formaat ongeldig is.
($pos = strpos($contact, '@')) ? substr($contact, 0, $pos) : error('Invalid contact: '.esc($contact))method
%WhatsApp -> isGroup ($contact)
line 15
Controleert of de opgegeven contactpersoon een WhatsApp-groep is door te verifiëren of de contactpersoon een '@g' achtervoegsel bevat.
last($this->number($contact), (bool)strpos($contact, '@g'))method
%WhatsApp -> status
line 17
Haal de huidige status van WhatsApp op met een GET-verzoek.
$this->request('status', GET: true)method
%WhatsApp -> health
line 18
Controleert de gezondheidsstatus van de WhatsApp-service door een GET-verzoek te verzenden.
$this->request('health', GET: true)method
%WhatsApp -> qr
line 19
Stuurt een verzoek om de QR-code voor WhatsApp-authenticatie op te halen.
$this->request('qr', GET: true)method
%WhatsApp -> disconnect
line 20
Verbreekt de huidige WhatsApp-sessie door een verbreekverzoek te sturen.
$this->request('disconnect')method
%WhatsApp -> read ($chat)
line 22
Stuurt een verzoek om berichten te lezen uit een opgegeven WhatsApp-chat.
$this->request('read', chat: $chat)method
%WhatsApp -> reaction ($msg, $emoji)
line 23
Stuurt een reactie-emoticon naar een specifiek bericht in WhatsApp.
$this->request('reaction', msg: $msg, emoji: $emoji)method
%WhatsApp -> text ($to, $text)
line 25
Verzendt een tekstbericht naar de opgegeven ontvanger via WhatsApp.
$this->request('text', to: $to, text: $text)method
%WhatsApp -> image ($to, file $file, $text = void)
line 26
Verzendt een afbeeldingsbericht via WhatsApp naar de opgegeven ontvanger, met de optie om een tekstbericht toe te voegen.
$this->request('image', to: $to, filename: $file->name, image: $file->src, text: $text)method
%WhatsApp -> location ($to, $lat, $lon, $text)
line 27
Verzendt een locatiebericht via WhatsApp naar de opgegeven ontvanger met breedtegraad, lengtegraad en optionele tekst.
$this->request('location', to: $to, lat: $lat, lon: $lon, text: $text)method
%WhatsApp -> document ($to, file $file, $text = void)
line 28
Verzendt een document via WhatsApp naar de opgegeven ontvanger, inclusief een optioneel tekstbericht.
$this->request('document', to: $to, filename: $file->name, document: $file->src, text: $text)method
%WhatsApp -> audio ($to, file $file)
line 30
Verzendt een audiobericht naar een opgegeven ontvanger met het opgegeven audiobestand.
$this->request('audio', to: $to, audio: $file->src)method
%WhatsApp -> voice ($to, file $file)
line 31
Verzendt een spraakbericht naar een opgegeven ontvanger met behulp van het opgegeven audiobestand.
$this->request('voice', to: $to, audio: $file->src)method
%WhatsApp -> poll ($to, $name, array $options, bool $multi = false)
line 33
Verzendt een peilingbericht naar een opgegeven WhatsApp-ontvanger met de gegeven opties, met de mogelijkheid voor meerdere selecties indien opgegeven.
$this->request('poll', to: $to, name: $name, options: $options, multi: $multi)method
%WhatsApp -> startTyping ($to)
line 35
Start de typindicator voor een opgegeven ontvanger in WhatsApp.
$this->request('typing/start', to: $to)method
%WhatsApp -> stopTyping ($to)
line 36
Stop de typindicator voor een specifieke ontvanger in WhatsApp.
$this->request('typing/stop', to: $to)method
%WhatsApp -> request ($action, ...$data)
line 38
Verzendt een verzoek naar de WhatsApp API met de opgegeven actie en gegevens, en retourneert een responsobject dat succes of falen aangeeft.
$get = $data['GET'] ?? false
unset($data['GET'])
$raw = trim((string)HTTP($this->url.$action, ['secret: '.$this->secret], true, $get ? null : $data))
if (strtolower($raw) === 'ok') return obj(ok: true)
$res = json_decode($raw)
if (!$res && $raw) return obj(ok: false, error: $raw)
return $res ?: obj(ok: false, error: 'Empty WhatsApp response')Functions
function
active(bool $cond, string $classList = void)
/phlo/resources/active.phlo line 7
Genereert een class-attribuutstring voor HTML-elementen, waarbij 'active' aan de opgegeven classlijst wordt toegevoegd als de voorwaarde waar is.
$cond || $classList ? ' class="'.$classList.($cond ? ($classList ? space : void).'active' : void).'"' : voidfunction
age(int $time)
/phlo/resources/age.phlo line 7
Berechnet de leeftijd door de gegeven tijd van de huidige tijd af te trekken.
time() - $timefunction
age_human(int $age)
/phlo/resources/age.human.phlo line 8
Berechnet een leesbare tijdsduur op basis van de gegeven leeftijd in seconden.
time_human(time() - $age)function
apcu($key, $cb, int $duration = 3600, bool $log = true)
/phlo/resources/apcu.phlo line 8
Cache een waarde met behulp van APCu met een opgegeven sleutel en callback, met een duur en optionele logging.
first($value = apcu_entry($key, $cb, $duration), $log && debug('C: '.(strlen($key) > 58 ? substr($key, 0, 55).'...' : $key).(is_array($value) ? ' ('.count($value).')' : (is_numeric($value) ? ":$value" : (is_string($value) ? ':string:'.strlen($value) : colon.gettype($value))))))function
await(...$jobs)
/phlo/resources/await.phlo line 10
Voert meerdere taken asynchroon uit en verzamelt hun resultaten, waarbij eventuele fouten die tijdens de uitvoering optreden worden afgehandeld.
$children = []
foreach ($jobs AS $i => $job){
[$cb, $args] = is_array($job) ? [$job[0], array_slice($job, 1)] : [$job, []]
$cmd = cli.space.escapeshellarg((string)$_SERVER['SCRIPT_FILENAME']).space.escapeshellarg($cb).loop($args, fn($a) => space.escapeshellarg((string)$a), void)
$desc = [0 => ['pipe','r'], 1 => ['pipe','w'], 2 => ['pipe','w']]
$proc = proc_open($cmd, $desc, $pipes)
fclose($pipes[0])
$children[$i] = obj(proc: $proc, out: $pipes[1], err: $pipes[2])
}
$results = []
foreach ($children AS $i => $child){
$out = stream_get_contents($child->out)
$err = stream_get_contents($child->err)
fclose($child->out)
fclose($child->err)
$code = proc_close($child->proc)
$err = trim((string)$err)
if ($err !== void){
$ej = json_decode($err, true)
$results[$i] = json_last_error() === JSON_ERROR_NONE ? $ej : $err
continue
}
if ($code !== 0){
$results[$i] = obj(error: 'CLI process failed', code: $code)
continue
}
$json = json_decode($out, true)
$results[$i] = json_last_error() === JSON_ERROR_NONE ? $json : $out
}
return $resultsfunction
button(...$args):string
/phlo/resources/tags.form.phlo line 10
Maakt een knop element met de opgegeven argumenten die als props worden doorgegeven.
tag('button', ...$args)function
camel(string $text)
/phlo/resources/camel.phlo line 7
Converteert een gegeven string naar camel case door de eerste letter van elk woord te kapitaliseren en spaties te verwijderen.
lcfirst(str_replace(space, void, ucwords(lcfirst($text))))function
chunk(...$cmds):void
/phlo/resources/chunk.phlo line 8
Deze functie verwerkt een set commando's, behandelt debug-informatie en beheert de respons voor streaminguitvoer in een specifiek formaat.
$res = %res
$cli = %req->cli
if (debug){
$res->dump && [$cmds['dump'] = $res->dump, $res->dump = []]
$res->debug && [$cmds['debug'] = $res->debug, $res->debug = []]
}
if (!$res->streaming){
$res->streaming = true
$res->type = 'text/event-stream'
$res->header('Cache-Control', 'no-store')
$res->header('X-Content-Type-Options', 'nosniff')
$res->render(206)
}
print(json_encode($cmds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).lf)
$cli || [@ob_flush(), flush()]function
create(iterable $items, \Closure $keyCb, ?\Closure $valueCb = null)
/phlo/resources/create.phlo line 7
Maakt een associatieve array door de waarden uit de iterable als sleutels te gebruiken en de optionele waarde callback te gebruiken om de bijbehorende waarden te bepalen.
array_combine(loop($items, $keyCb), $valueCb ? loop($items, $valueCb) : $items)function
en($text, ...$args)
/phlo/resources/lang.phlo line 12
Deze functie haalt een vertaling op voor de opgegeven tekst in het Engels, en kan optioneel worden opgemaakt met extra argumenten.
%lang->translation('en', $text, ...$args)function
exec_stream(string $cmd, ?int $timeoutSec = 0)
/phlo/resources/exec.stream.phlo line 9
Voert een opdracht uit in een apart proces en streamt de uitvoer en foutmeldingen asynchroon, waarbij ze als objecten worden opgeleverd. Het ondersteunt ook een time-outfunctie om het proces te beëindigen als het de opgegeven duur overschrijdt.
$desc = [0 => ['pipe','r'], 1 => ['pipe','w'], 2 => ['pipe','w']]
$proc = proc_open($cmd, $desc, $pipes)
if (!is_resource($proc)) return
stream_set_blocking($pipes[1], false)
stream_set_blocking($pipes[2], false)
$bufOut = void
$bufErr = void
while (true){
$status = proc_get_status($proc)
$running = $status['running']
$read = []
$w = null
$e = null
if (!feof($pipes[1])) $read[] = $pipes[1]
if (!feof($pipes[2])) $read[] = $pipes[2]
if ($read) @stream_select($read, $w, $e, 0, 200000)
foreach ($read AS $r){
$chunk = fread($r, 8192)
if ($chunk === void || $chunk === false) continue
if ($r === $pipes[1]){
$bufOut .= $chunk
while (($pos = strpos($bufOut, lf)) !== false){
$line = substr($bufOut, 0, $pos)
$bufOut = substr($bufOut, $pos + 1)
yield obj(data: $line)
}
}
else {
$bufErr .= $chunk
while (($pos = strpos($bufErr, lf)) !== false){
$line = substr($bufErr, 0, $pos)
$bufErr = substr($bufErr, $pos + 1)
yield obj(data: $line, error: true)
}
}
}
if (!$running) break
if ($timeoutSec > 0 && ($status['running_time'] ?? 0) > $timeoutSec){
proc_terminate($proc)
yield obj(data: 'process timeout', error: true)
break
}
}
if ($bufOut !== void) yield obj(data: $bufOut)
if ($bufErr !== void) yield obj(data: $bufErr, error: true)
foreach ($pipes AS $p) @fclose($p)
proc_close($proc)function
HTTP(string $url, array $headers = [], bool $JSON = false, $POST = null, $PUT = null, $PATCH = null, bool $DELETE = false, ?string $agent = null)
/phlo/resources/HTTP.phlo line 8
Verzendt een HTTP-verzoek naar de opgegeven URL met optionele headers en ondersteunt verschillende methoden, waaronder GET, POST, PUT, PATCH en DELETE.
$curl = curl_init($url)
if ($POST !== null || $PUT !== null || $PATCH !== null){
if (!is_null($POST)) [$method = 'POST', $content = $POST]
elseif (!is_null($PUT)) [$method = 'PUT', $content = $PUT]
elseif (!is_null($PATCH)) [$method = 'PATCH', $content = $PATCH]
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method)
if ($JSON) [!is_string($content) && $content = json_encode($content), array_push($headers, 'Content-Type: application/json', 'Content-Length: '.strlen($content))]
curl_setopt($curl, CURLOPT_POSTFIELDS, $content)
}
elseif ($DELETE) curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE')
$agent && curl_setopt($curl, CURLOPT_USERAGENT, $agent === true ? phlo('req')->userAgent : $agent)
curl_setopt_array($curl, [CURLOPT_COOKIEFILE => data.'cookies.txt', CURLOPT_COOKIEJAR => data.'cookies.txt', CURLOPT_HTTPHEADER => $headers, CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 15, CURLOPT_ENCODING => void])
$res = curl_exec($curl)
if ($res === false) error('HTTP error: '.curl_error($curl))
return $resfunction
input(...$args):string
/phlo/resources/tags.form.phlo line 11
Maakt een invoerelement in de view met de opgegeven argumenten.
tag('input', ...$args)function
n8n($webhook, ?array $data = null, $test = false)
/phlo/resources/n8n.phlo line 8
Stuurt een HTTP POST-verzoek naar een n8n webhook met optionele gegevens en een testvlag.
HTTP(%creds->n8n->server.'webhook'.($test ? '-test' : '').'/'.$webhook, POST: $data)function
n8n_test($webhook, ?array $data = null)
/phlo/resources/n8n.test.phlo line 8
Deze functie activeert een n8n-workflow met de opgegeven webhook en een optionele gegevensarray, en retourneert het resultaat van de n8n-aanroep.
n8n($webhook, $data, true)function
nl($text, ...$args)
/phlo/resources/lang.phlo line 11
Vertaal de gegeven tekst naar het Nederlands met de opgegeven argumenten voor opmaak.
%lang->translation('nl', $text, ...$args)function
notify(string $title, string $body = '', string $type = 'info', string $level = 'info', ?string $user = null):void
/phlo/resources/notify.phlo line 9
Verzendt een melding met een opgegeven titel, inhoud, type, niveau en optionele gebruiker naar een geconfigureerde URL via HTTP.
$cfg = %creds->notify ?? null
if (!$cfg) return
$url = (string)($cfg->url ?? void)
$secret = (string)($cfg->secret ?? void)
if ($url === void || $secret === void) return
try {
HTTP($url, ['secret: '.$secret], true, [
'app' => (string)($cfg->app ?? (defined('id') ? id : 'app')),
'server' => (string)($cfg->server ?? 'local'),
'host' => (string)(%req->host ?? ''),
'type' => $type,
'level' => $level,
'title' => $title,
'body' => $body,
'user' => $user,
])
}
catch (\Throwable $e){}function
phlo(?string $phloName = null, ...$args):mixed
/phlo/phlo.php line 190
Maakt of haalt een instantie van een Phlo-object op op basis van de opgegeven naam en argumenten, en beheert een statische lijst van objecten voor efficiënte toegang.
static $list = [];
if ($phloName === 'tech/reset') return array_keys($list = array_filter($list, static fn($obj) => $obj->objPers));
if ($phloName === null) return array_keys($list);
$class = strtr($phloName, [slash => us]);
$handle = method_exists($class, '__handle') ? $class::__handle(...$args) : ($args ? null : $phloName);
if ($handle === true){
if (isset($list[$phloName])) return $list[$phloName]->objImport(...$args);
$handle = $phloName;
}
elseif ($handle && isset($list[$handle])) return $list[$handle];
$object = new $class(...$args);
if ($handle) $list[$handle] = $object;
if ($object->hasMethod('controller') && (!phlo('req')->cli || $phloName !== 'app')) $object->controller();
return $object;function
phlo_app(...$args):void
/phlo/phlo.php line 38
Initialiseert de Phlo-applicatie met opgegeven argumenten, stelt noodzakelijke configuraties in, laadt klassen automatisch en behandelt fouten en uitzonderingen.
if ($args['trace'] ??= false) require_once __DIR__.'/classes/trace.php';
require_once __DIR__.'/functions'.($args['trace'] ? '.trace.php' : '.php');
require_once __DIR__.'/classes/obj.php';
require_once __DIR__.'/classes/req.php';
require_once __DIR__.'/classes/res.php';
$args['app'] ?? error('No "app" path defined');
$args['debug'] ??= false;
$args['build'] ??= false;
$args['host'] ??= null;
$args['control'] ??= ($args['build'] && $args['debug']) ? 'phlo' : false;
$args['auth'] ??= false;
$args['data'] ??= $args['app'].'data/';
$args['php'] ??= $args['app'].'php/';
$args['www'] ??= $args['app'].'www/';
$args['cli'] ??= ZEND_THREAD_SAFE ? 'php-zts' : 'php';
$args['thread'] ??= false;
$args['build'] && $args['thread'] && error('Phlo build and thread mode cannot be combined');
$args['build'] && !is_file($args['data'].'app.json') && error('Phlo build mode requires data/app.json');
$args['auth'] && !$args['build'] && error('Auth requires build mode');
foreach ($args as $key => $value) define($key, $value);
define('engine', __DIR__.slash);
if ($args['debug']) require_once __DIR__.'/debug.php';
if ($args['build']) require_once __DIR__.'/classes/changed.php';
if ($args['trace']) trace::boot($args['app']);
set_error_handler(static function(int $level, string $msg, string $file = '', int $line = 0):bool {
if (!(error_reporting() & $level)) return false;
throw new ErrorException($msg, 0, $level, $file, $line);
});
set_exception_handler('phlo_exception');
spl_autoload_register(static function(string $class):void {
static $map = null, $mtime = null;
$file = php.'classmap.php';
if ($map === null || $mtime !== (is_file($file) ? filemtime($file) : null)){
$map = is_file($file) ? require $file : [];
$mtime = is_file($file) ? filemtime($file) : null;
}
if (isset($map[$class])){ require_once php.$map[$class]; return; }
});
if ($args['build']){
$engineMap = ['build' => 'build', 'reflect' => 'reflect', 'build_file' => 'file', 'build_node' => 'node', 'build_builder' => 'builder', 'build_css' => 'css', 'build_icons' => 'icons'];
spl_autoload_register(static function(string $class) use ($engineMap):void {
$name = $engineMap[strtolower($class)] ?? null;
if ($name !== null) require_once engine.'classes/'.$name.'.php';
});
}
defined('composer') && spl_autoload_register(static function(string $class):void {
static $loaded = false;
if ($loaded) return;
$loaded = true;
require_once composer.'vendor/autoload.php';
foreach (spl_autoload_functions() as $fn){
if (is_array($fn) && ($fn[0] ?? null) instanceof \Composer\Autoload\ClassLoader){
spl_autoload_unregister($fn);
spl_autoload_register($fn);
$fn[0]->loadClass($class);
return;
}
}
});
if ($args['thread'] !== false && PHP_SAPI !== 'cli'){
ignore_user_abort(true);
$handle = static function():void { phlo_thread(); };
for ($i = 1; !$args['thread'] || $i <= $args['thread']; ++$i){
$keepRunning = frankenphp_handle_request($handle);
phlo('tech/reset');
if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
gc_collect_cycles();
if (!$keepRunning) break;
}
return;
}
phlo_thread();function
phlo_async(string $cb, ...$args)
/phlo/resources/phlo.async.phlo line 8
Voert een callbackfunctie asynchroon op de achtergrond uit, waarbij eventuele extra argumenten worden doorgegeven, en retourneert de proces-ID van het opgestarte proces.
last($cmd = cli.space.escapeshellarg((string)$_SERVER['SCRIPT_FILENAME']).space.escapeshellarg($cb).loop($args, fn($a) => space.escapeshellarg((string)$a), void).' > /dev/null 2>&1 & echo $!', exec($cmd, $r), isset($r[0]) && ctype_digit($r[0]) && (int)$r[0] > 0)function
phlo_cli(array $args):void
/phlo/phlo.php line 174
Voert een methode of functie uit die is opgegeven in de `$args` array en geeft het resultaat weer als een JSON-string.
if (!$args) return;
$target = array_shift($args);
if (str_contains($target, dot)){
[$object, $method] = explode(dot, $target, 2);
$handle = phlo($object);
$result = $args ? $handle->$method(...$args) : ($handle->hasMethod($method) ? $handle->$method() : $handle->$method);
}
elseif (str_contains($target, '::')){
[$class, $method] = explode('::', $target, 2);
$result = $class::$method(...$args);
}
else $result = $target(...$args);
if (isset($result)) print(json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).lf);function
phlo_exception(Throwable $e):void
/phlo/phlo.php line 33
Behandelt uitzonderingen door het Throwable-object door te geven aan de phlo_error_handle functie voor verwerking.
require_once engine.'error.php';
phlo_error_handle($e);function
phlo_exists(string $obj)
/phlo/resources/phlo.exists.phlo line 7
Controleert of een specifiek PHP-bestand bestaat op het opgegeven objectpad.
is_file(php.strtr($obj, [us => dot]).'.php')function
phlo_load(bool $http):void
/phlo/phlo.php line 151
Laadt de noodzakelijke runtime-bestanden voor de applicatie, waarbij ervoor wordt gezorgd dat de applicatie slechts eenmaal wordt geladen en dat het juiste contenttype wordt ingesteld voor HTTP-responses.
static $loaded = false, $loadedApp = null;
if ($loaded && $loadedApp === app){
if ($http && !phlo('res')->type) phlo('res')->type = 'text/html; charset=UTF-8';
return;
}
if (build && (!is_file(php.'functions.php') || !is_file(php.'app.php') || build_base::changed())){
debug('Builder started');
$changed = build::run();
$changed && debug('Built '.implode(', ', array_map('basename', $changed)).' ('.count($changed).')');
}
if (!is_file(php.'functions.php') || !is_file(php.'app.php')) error('Compiled runtime not available');
if (!$loaded){
require_once php.'functions.php';
$loaded = true;
}
if ($loadedApp !== app){
require_once php.'app.php';
$loadedApp = app;
}
if ($http && !phlo('res')->type) phlo('res')->type = 'text/html; charset=UTF-8';function
phlo_stream(string $cb, ...$args)
/phlo/resources/phlo.stream.phlo line 10
Voert een callback uit op een streaming manier en geeft extra argumenten door terwijl de output wordt teruggegeven.
yield from exec_stream(cli.space.escapeshellarg((string)$_SERVER['SCRIPT_FILENAME']).space.escapeshellarg($cb).loop($args, fn($a) => space.escapeshellarg((string)$a), void))function
phlo_sync(string $cb, ...$args)
/phlo/resources/phlo.sync.phlo line 8
Voert een opgegeven callbackfunctie uit in de CLI-context met de meegeleverde argumenten en retourneert het resultaat als een JSON-object, waarbij fouten op de juiste manier worden afgehandeld.
$cmd = cli.space.escapeshellarg((string)$_SERVER['SCRIPT_FILENAME']).space.escapeshellarg($cb).loop($args, fn($a) => space.escapeshellarg((string)$a), void)
exec($cmd.' 2>&1', $r, $code)
$out = implode(lf, $r)
$j = json_decode($out, true)
if ($code !== 0) error('Could not execute "'.esc($cb).'" via CLI')
if (json_last_error() !== JSON_ERROR_NONE) return $out
if (is_array($j) && isset($j['error'])) error((string)$j['error'])
return $jfunction
phlo_thread():void
/phlo/phlo.php line 113
Beheert de hoofd uitvoeringsstroom van een Phlo-applicatie, inclusief verzoeken voor zowel CLI- als webomgevingen, met inbegrip van authenticatie en dashboardweergave.
try {
$req = phlo('req');
if ($req->cli){
$target = $req->args[0] ?? void;
if (str_starts_with($target, 'build::') || str_starts_with($target, 'reflect::')){
phlo_cli($req->args);
return;
}
phlo_load(false);
phlo('app');
phlo_cli($req->args);
return;
}
$isDashboard = build && debug && control && str_starts_with($req->path.slash, control.slash);
if (auth && !$isDashboard){
phlo_auth('site', 'Phlo App - '.host);
if (phlo('res')->done) return;
}
if ($isDashboard){
require_once engine.'control.php';
phlo_dashboard::handle(substr($req->path, strlen(control) + 1));
phlo('res')->render();
return;
}
phlo_load(true);
phlo('app');
phlo('res')->render();
}
catch (RuntimeException $e){
if ($e->getMessage() === 'PhloDump' || $e->getMessage() === 'PhloStop') return;
phlo_exception($e);
}
catch (Throwable $e){
phlo_exception($e);
}function
select(...$args):string
/phlo/resources/tags.form.phlo line 12
Maakt een 'select' HTML-element met de opgegeven argumenten als attributen en opties.
tag('select', ...$args)function
slug(string $text)
/phlo/resources/slug.phlo line 7
Converteert een gegeven string naar een URL-vriendelijke slug door niet-alfanumerieke tekens te verwijderen, naar kleine letters om te zetten en spaties door streepjes te vervangen.
trim(preg_replace('/[^a-z0-9]+/', dash, strtolower(iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text))), dash)function
tag(string $tagName, ?string $inner = null, ...$args)
/phlo/resources/tag.phlo line 8
Genereert een HTML-tag met de opgegeven naam, optionele inhoud en extra attributen.
"<$tagName".loop(array_filter($args, fn($value) => !is_null($value)), fn($value, $key) => space.strtr($key, [us => dash]).($value === true ? void : '="'.esc($value).'"'), void).'>'.(is_null($inner) ? void : "$inner</$tagName>")function
textarea(...$args):string
/phlo/resources/tags.form.phlo line 13
Maakt een 'textarea' HTML-element met de opgegeven argumenten.
tag('textarea', ...$args)function
time_human(?int $time = null)
/phlo/resources/time.human.phlo line 7
Converteert een gegeven tijdstempel naar een leesbaar tijdsverschil formaat, zoals '2 dagen' of '3 uur'. Als er geen tijdstempel wordt opgegeven, wordt de huidige tijd gebruikt.
static $labels
$labels ??= last($labels = arr(seconds: 60, minutes: 60, hours: 24, days: 7, weeks: 4, months: 13, years: 1), defined('tsLabels') && $labels = array_combine(tsLabels, $labels), $labels)
$age = time() - $time
foreach ($labels AS $range => $multiplier){
if ($age / $multiplier < 1.6583) break
$age /= $multiplier
}
return round($age)." $range"function
wsCast($wsTarget = 'all', $wsHost = host, $wsPort = websocket, ...$data)
/phlo/resources/wsCast.phlo line 8
Verzendt een bericht naar een opgegeven WebSocket-doel, waarmee gegevens via de WebSocket-verbinding kunnen worden verzonden.
HTTP (
'http://127.0.0.1:'.$wsPort.'/message',
JSON: true,
POST: arr (
host: $wsHost,
target: $wsTarget,
data: $data,
),
)