files
object
%CSV
/phlo/resources/files/CSV.phlo
static
CSV :: __handle
line 10
CSV::$__handle is a reference to the file handle used for reading or writing CSV data located at the specified path and filename.
"CSV/$path$filename"method
%CSV -> __construct (string $filename, ?string $path = null)
line 11
Initializes a CSV object by constructing the file path from the given filename and optional path, defaulting to 'data'. If the constructed file is readable, it calls the objRead method to read the CSV data.
$path ??= data
$this->objFile = $path.strtr($filename, [slash => dot]).'.csv'
if (is_readable($this->objFile)) $this->objRead()readonly
%CSV -> objFile:string
line 17
Converts a CSV file into an obj representation for easier manipulation within Phlo.
method
%CSV -> objRead:void
line 19
Reads a CSV file and converts its contents into an associative array of objects, using the first row as headers.
$fp = fopen($this->objFile, 'r+')
$headers = str_replace([dq, cr, lf], void, fgets($fp))
$delimiter = substr_count($headers, comma) > substr_count($headers, semi) ? comma : semi
$headers = explode($delimiter, $headers)
while ($row = fgetcsv($fp, null, $delimiter, dq, void)) $this->objData[] = array_combine($headers, $row)
fclose($fp)object
%DOCX
/phlo/resources/files/DOCX.phlo
method
%DOCX -> __construct (string $file)
line 11
Initializes a DOCX object by opening the specified DOCX file, extracting the text from 'word/document.xml', and processing it into paragraphs.
$zip = new ZipArchive()
if ($zip->open($file) !== true) dx('error opening docx', $file)
$xml = $zip->getFromName('word/document.xml')
$zip->close()
if (!$xml) dx('error reading document.xml')
$text = preg_replace('/<\/w:p>/', lf, $xml)
$text = strip_tags($text)
$text = html_entity_decode($text, ENT_QUOTES | ENT_XML1, 'UTF-8')
$this->text = trim(preg_replace('/[ \t]+/', space, $text))
$this->paragraphs = array_values(array_filter(explode(lf, $this->text), fn($p) => trim($p) !== void))static
DOCX :: toText (string $file):string
line 24
Converts the contents of a DOCX file into plain text format.
(new static($file))->textobject
%file
/phlo/resources/files/file.phlo
static
file :: __handle
line 10
This expression constructs a file path by concatenating 'file/$file' with the optional name, if provided.
"file/$file".($name ? "/$name" : void)method
%file -> __construct (public string $file, ?string $name = null, $contents = null, ...$args)
line 11
Initializes a file object with a specified filename, an optional name, and optional contents, while also allowing additional arguments for object import.
$name && $this->name = $name
is_string($contents) && $this->write($contents)
$args && $this->objImport(...$args)method
%file -> append (string $data):int|false
line 17
Appends the specified string data to the end of the file, ensuring exclusive access during the operation.
file_put_contents($this->file, $data, FILE_APPEND | LOCK_EX)prop
%file -> basename:string
line 18
Returns the base name of the file from the given file path.
pathinfo($this->file, PATHINFO_BASENAME)method
%file -> base64:string
line 19
Encodes the contents of a file into a Base64 string.
base64_encode($this->contents)method
%file -> contents:string|false
line 20
Reads the entire contents of a file into a string.
file_get_contents($this->file)method
%file -> contentsINI (bool $parse = true):array|false
line 21
Reads the contents of a file and parses it as an INI string, returning an associative array. The $parse parameter determines whether to use typed or raw scanning for the INI data.
parse_ini_string($this->contents, true, $parse ? INI_SCANNER_TYPED : INI_SCANNER_RAW)method
%file -> contentsJSON ($assoc = null)
line 22
Decodes the JSON string stored in the contents property into a PHP variable, optionally returning an associative array if the $assoc parameter is set to true.
json_decode($this->contents, $assoc)method
%file -> copy ($to):bool
line 23
Copies the file represented by the current object to the specified destination path.
copy($this->file, $to)method
%file -> created:int|false
line 24
Returns the Unix timestamp of the last time the file was created.
filectime($this->file)method
%file -> createdAge:int
line 25
Returns the age of the file based on its creation timestamp.
age($this->created)method
%file -> createdHuman:string
line 26
Returns a human-readable representation of the file's creation time.
time_human($this->created)method
%file -> curl ($type = null, $filename = null):CURLFile
line 27
Creates a new CURLFile object for file uploads in a cURL request, allowing specification of the file type and filename.
new CURLFile($this->file, $type, $filename)method
%file -> delete:bool
line 28
Deletes the specified file if it exists and returns a debug message indicating the success or failure of the operation.
first($deleted = $this->exists && unlink($this->file), debug($deleted ? "Deleted $this->basename" : "Could not delete $this->basename"))method
%file -> exists:bool
line 29
Checks if the specified file exists in the filesystem.
file_exists($this->file)prop
%file -> ext:string
line 30
Retrieves the file extension from the file name stored in the 'name' property using PHP's pathinfo function.
pathinfo($this->name, PATHINFO_EXTENSION)prop
%file -> filename:string
line 31
Extracts the filename from the file path stored in the 'file' property.
pathinfo($this->file, PATHINFO_FILENAME)method
%file -> getLine:string|false
line 32
Retrieves a single line from a file pointer, returning false on failure or the line without trailing whitespace on success.
($line = fgets($this->pointer)) === false ? false : rtrim($line)method
%file -> getLength (int $length):string|false
line 33
Retrieves the length of the file by reading a specified number of bytes from the file pointer.
fread($this->pointer, $length)method
%file -> is (string $file):bool
line 34
Checks if the specified file matches the current file instance.
$file === $this->filemethod
%file -> md5:string|false
line 35
Calculates the MD5 hash of the specified file.
md5_file($this->file)prop
%file -> mime:string
line 36
Returns the MIME type of the file based on its name.
mime($this->name)method
%file -> modified:int|false
line 37
Returns the last modified time of the specified file as a Unix timestamp.
filemtime($this->file)method
%file -> modifiedAge:int
line 38
Returns the age of the file based on its last modified timestamp.
age($this->modified)method
%file -> modifiedHuman:string
line 39
Returns a human-readable representation of the file's last modified time.
time_human($this->modified)method
%file -> move ($to):bool
line 40
Moves the current file to a new location specified by $to, updating the file reference upon success.
rename($this->file, $to) && $this->file = $toprop
%file -> name:string
line 41
This retrieves the basename of the file represented by the object, which is the name of the file without any directory path.
$this->basenamemethod
%file -> output ($download = false)
line 42
Outputs the contents of a file, allowing the option to download it if specified.
output($this->contents, $this->name, $download)prop
%file -> path:string
line 43
This retrieves the directory path of the specified file and appends a slash to it.
realpath(pathinfo($this->file, PATHINFO_DIRNAME)).slashprop
%file -> pathRel:string
line 44
This expression returns the relative path of a file by checking if the file path starts with 'app' and, if so, removes that prefix; otherwise, it returns the original file path.
str_starts_with($this->file, app) ? substr($this->file, strlen(app)) : $this->fileprop
%file -> pointer
line 45
Opens the specified file in read and write mode, returning a pointer to the file resource.
fopen($this->file, 'r+')method
%file -> readable:bool
line 46
Checks if the specified file is readable.
is_readable($this->file)method
%file -> src:string
line 47
This expression generates a data URI for a file, combining its MIME type and base64-encoded content.
"data:$this->mime;base64,$this->base64"method
%file -> size:int|false
line 48
Returns the size of the specified file in bytes.
filesize($this->file)method
%file -> sizeHuman (int $precision = 0):string
line 49
Converts a file size in bytes to a human-readable format, with an optional precision for decimal places.
size_human($this->size, $precision)method
%file -> sha1:string|false
line 50
Calculates the SHA-1 hash of the specified file.
sha1_file($this->file)method
%file -> shortenTo (int $length):string
line 51
Shortens the file name to a specified length while preserving the file extension, adding ellipsis if the name is truncated.
strlen($this->name) <= $length ? $this->name : substr($this->name, 0, $length - strlen($this->ext) - 3).dot.dot.dot.$this->extmethod
%file -> title:string
line 52
Extracts the title from the file name by converting it to a human-readable format, replacing underscores with spaces and capitalizing the first letter.
ucfirst(strtr(pathinfo($this->name, PATHINFO_FILENAME), [us => space]))method
%file -> token ($length = 20):string
line 53
Generates a token of the specified length using SHA-1 hashing.
token($length, $this->sha1)method
%file -> type:string
line 54
Extracts the type of a file from its MIME type by retrieving the substring before the first slash.
substr($this->mime, 0, strpos($this->mime, slash))method
%file -> touch:bool
line 55
Creates a new file or updates the timestamp of an existing file specified by the file path.
touch($this->file)method
%file -> writable:bool
line 56
Checks if the specified file is writable.
is_writable($this->file)method
%file -> writeINI ($data, bool $deleteEmpty = false):bool
line 57
Writes data to an INI file format. The optional parameter allows for the deletion of empty sections if set to true.
$this->write(!$deleteEmpty || $data ? loop($data, fn($value, $key) => $key.' = '.dq.strtr($value, [dq => bs.dq, lf => '\n']).dq, lf).lf : void, $deleteEmpty)method
%file -> writeJSON ($data, bool $deleteEmpty = false):bool
line 58
$this->write(!$deleteEmpty || $data ? json_encode($data, jsonPretty) : void, $deleteEmpty)method
%file -> writeJSONplain ($data, bool $deleteEmpty = false):bool
line 59
Writes the provided data as a JSON string to a file, optionally deleting empty entries based on the deleteEmpty flag.
$this->write(!$deleteEmpty || $data ? json_encode($data) : void, $deleteEmpty)method
%file -> write (string $data, bool $deleteEmpty = false):bool
line 60
Writes the specified string data to a file, with an option to delete the file if the data is empty.
if (!$data && $deleteEmpty) return $this->delete
if ($written = file_put_contents($this->file, $data, LOCK_EX) !== false) debug('Written '.$this->basename.' ('.$this->sizeHuman.')')
else error('Could not write '.$this->file)
return $writtenmethod
%file -> objInfo:array
line 67
Creates an object containing information about a file, including its name, existence, and optionally its size, creation date, modification date, and MIME type if it exists.
array_combine($keys = array_merge(['file', 'name', 'exists'], $this->exists ? ['sizeHuman', 'createdHuman', 'modifiedHuman', 'mime'] : []), loop($keys, fn($arg) => $this->$arg))object
%img
/phlo/resources/files/img.phlo
static
img :: detect ($data):?string
line 10
Detects the image format of a given binary data by examining its header and returns the corresponding format as a string.
$header = substr($data, 0, 12)
if (substr($header, 0, 3) === "\xFF\xD8\xFF") return 'jpg'
if (substr($header, 0, 8) === "\x89PNG\x0D\x0A\x1A\x0A") return 'png'
if (substr($header, 0, 6) === 'GIF87a' || substr($header, 0, 6) === 'GIF89a') return 'gif'
if (substr($header, 0, 4) === 'RIFF' && substr($header, 8, 4) === 'WEBP') return 'webp'
if (substr($header, 0, 2) === "BM") return 'bmp'
if (substr($header, 0, 4) === "\x49\x49\x2A\x00" || substr($header, 0, 4) === "\x4D\x4D\x00\x2A") return 'tiff'static
img :: __handle
line 20
This retrieves the image resource from the specified file path.
"img/$file"method
%img -> __construct (public string $file)
line 21
Initializes an img object with a public string property $file representing the file path of the image.
prop
%img -> src:GdImage
line 23
This function creates an image resource from a string containing image data, typically loaded from a file.
imagecreatefromstring(file_get_contents($this->file))prop
%img -> width:int
line 24
Retrieves the width of an image resource specified by the `src` property.
imagesx($this->src)prop
%img -> height:int
line 25
Returns the height of the image specified by the `src` property.
imagesy($this->src)method
%img -> scale ($width = null, $height = null, $crop = false):static
line 27
Scales the image to the specified width and height, optionally cropping it based on the provided parameters.
if (!$width && !$height) return $this
$srcW = $this->width
$srcH = $this->height
$doCrop = ($crop && $width && $height)
if ($width && $height) $scale = $doCrop ? max($width / $srcW, $height / $srcH) : min($width / $srcW, $height / $srcH)
elseif ($width) $scale = $width / $srcW
else $scale = $height / $srcH
if ($scale >= 1) return $this
$scaledW = (int)round($srcW * $scale)
$scaledH = (int)round($srcH * $scale)
$destW = ($width && $height && $doCrop) ? (int)$width : $scaledW
$destH = ($width && $height && $doCrop) ? (int)$height : $scaledH
$offsetX = 0
$offsetY = 0
if ($width && $height && $doCrop){
$offsetX = (int)-round(($scaledW - $destW) / 2)
$offsetY = (int)-round(($scaledH - $destH) / 2)
if ($crop === 'top') $offsetY = 0
elseif ($crop === 'bottom') $offsetY = (int)-($scaledH - $destH)
}
$destImg = imagecreatetruecolor($destW, $destH)
imagealphablending($destImg, false)
imagesavealpha($destImg, true)
imagecopyresampled($destImg, $this->src, $offsetX, $offsetY, 0, 0, $scaledW, $scaledH, $srcW, $srcH)
$this->src = $destImg
$this->width = $destW
$this->height = $destH
return $thismethod
%img -> ext ($file = null):string
line 58
Returns the file extension of the specified file in lowercase. If no file is provided, it uses the instance's default file.
strtolower(pathinfo($file ?? $this->file, PATHINFO_EXTENSION))method
%img -> source ($format = null):string
line 60
Retrieves the source of an image in the specified format, or the default format if none is provided, by capturing the output of the write method.
ob_start()
$this->write($format)
return ob_get_clean()method
%img -> save ($file = null):bool
line 66
Saves the image to the specified file path if provided; otherwise, it writes the image to a default location.
$file && $this->file = $file
return $this->write(null, $this->file)method
%img -> write ($format = null, $file = null)
line 71
Writes the image to a file in the specified format, defaulting to JPEG if no format is provided. Supported formats include PNG, GIF, WebP, and JPEG.
$format ??= $this->ext()
if ($format === 'png') return imagepng($this->src, $file, 8)
if ($format === 'gif') return imagegif($this->src, $file)
if ($format === 'webp'){
imageistruecolor($this->src) || imagepalettetotruecolor($this->src)
return imagewebp($this->src, $file)
}
return imagejpeg($this->src, $file, 85)object
%INI
/phlo/resources/files/INI.phlo
prop
%INI -> objFile:string
line 10
INI->$objFile is used to create or access an INI file object for reading or writing configuration settings.
static
INI :: __handle
line 12
INI::$__handle retrieves the handle for the specified INI file, optionally parsing it based on the provided parameters.
"INI/$path$filename".(!$parse ? '/0' : void)method
%INI -> __construct (string $filename, ?string $path = null, bool $parse = true)
line 13
Initializes an INI object with a specified filename and optional path, and reads the file if it is accessible.
$path ??= data
$this->objFile = $path.strtr($filename, [slash => dot]).'.ini'
if (is_readable($this->objFile)) $this->objRead($parse)method
%INI -> objRead ($parse = true)
line 19
Reads an INI file and converts it into an obj, optionally parsing the values into their respective types.
last($this->objData = parse_ini_file($this->objFile, true, $parse ? INI_SCANNER_TYPED : INI_SCANNER_RAW), $this->objChanged = false, $this)method
%INI -> objWrite:int|false
line 20
Writes the current object data to an INI file format, ensuring that special characters are properly escaped and the file is locked during the write operation.
file_put_contents($this->objFile, loop($this->objData, fn($value, $key) => $key.' = '.dq.strtr($value, [dq => bs.dq, lf => '\n']).dq, lf).lf, LOCK_EX)method
%INI -> __destruct
line 22
The INI->__destruct method checks if the object has changed and calls the objWrite method if necessary to handle cleanup before the object is destroyed.
$this->objChanged && $this->objWrite()object
%JSON
/phlo/resources/files/JSON.phlo
static
JSON :: __handle
line 11
This function constructs a JSON file path based on the provided filename and an associative boolean flag, determining the format of the path.
"JSON/$path$filename".(is_bool($assoc) ? slash.(int)$assoc : void)method
%JSON -> __construct (string $filename, ?string $path = null, $assoc = null)
line 12
Constructs a JSON object from a specified filename and optional path, creating the full file path and reading the JSON data if the file is accessible.
$path ??= data
$this->objFile = $path.strtr($filename, [slash => dot]).'.json'
if (is_readable($this->objFile)) $this->objRead($assoc)readonly
%JSON -> objFile:string
line 18
Converts a JSON string into a Phlo obj for further manipulation or processing.
method
%JSON -> objTouch:bool
line 20
Sets the objChanged property to true, indicating that the object has been modified.
$this->objChanged = truemethod
%JSON -> objRead ($assoc = null)
line 21
Reads a JSON file and converts it into an object or an associative array based on the provided parameter.
last($data = json_read($this->objFile, $assoc), $this->objData = $assoc || is_array($data) ? $data : get_object_vars($data), $this->objChanged = false, $this)method
%JSON -> objWrite ($data, $flags = null)
line 22
Writes JSON data to an object file, optionally using specified flags to modify the write behavior.
first($written = json_write($this->objFile, $data, $flags), $written && $this->objChanged = false)method
%JSON -> __destruct
line 24
This method is called when an object is destroyed, ensuring that any changes to the object's data are written before it is removed from memory.
$this->objChanged && $this->objWrite($this->objData)object%PDF
/phlo/resources/files/PDF.phlo
static
PDF :: toText (string $file):string
line 10
$process = proc_open('pdftotext '.escapeshellarg($file).' -', [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes)
if (!is_resource($process)) error('PDFToText Error: could not start pdftotext')
fclose($pipes[0])
$text = stream_get_contents($pipes[1])
fclose($pipes[1])
$error = stream_get_contents($pipes[2])
fclose($pipes[2])
($code = proc_close($process)) && error("PDFToText Error: pdftotext command failed with code $code. Error: $error")
return rtrim($text, "\f")prop
%PDF -> title:?string
line 22
Generates a PDF document with the specified title.
nullprop
%PDF -> author:?string
line 23
Retrieves the author of the PDF document.
nullprop
%PDF -> subject:?string
line 24
Generates a PDF document based on the specified subject.
nullprop
%PDF -> keywords:?string
line 25
Generates a list of keywords extracted from a PDF document.
nullprop
%PDF -> creator:string
line 26
The PDF->$creator property retrieves the creator information of the PDF document.
'Phlo '.phlo.' (https://phlo.tech/)'prop
%PDF -> filename:string
line 28
This item specifies the filename 'Download.pdf' for a PDF resource.
'Download.pdf'prop
%PDF -> mode:string
line 29
Sets the mode for PDF processing, where 'D' indicates a specific mode of operation.
'D'method
%PDF -> fromHTML ($HTML):string
line 31
$mpdf = new \Mpdf\Mpdf
$this->title && $mpdf->SetTitle($this->title)
$this->author && $mpdf->SetAuthor($this->author)
$this->subject && $mpdf->SetSubject($this->subject)
$this->keywords && $mpdf->SetKeywords($this->keywords)
$this->creator && $mpdf->SetCreator($this->creator)
$mpdf->WriteHTML($HTML)
return (string)$mpdf->Output($this->filename, $this->mode)object
%UBL
/phlo/resources/files/UBL.phlo
static
UBL :: invoice (array $data):string
line 10
Generates a UBL invoice XML structure based on provided invoice data, including supplier and customer information, line items, tax calculations, and total amounts.
$currency = strtoupper((string)($data['currency'] ?? 'EUR'))
$issue = (string)($data['issue_date'] ?? void)
$due = (string)($data['due_date'] ?? void) ?: $issue
$lines = []
$linesSum = 0
$taxSubtotals = []
foreach ((array)($data['lines'] ?? []) AS $i => $line){
$qty = (float)($line['quantity'] ?? 0)
$net = round($qty * (float)($line['unit_price'] ?? 0), 2)
$rate = (float)($line['tax_rate'] ?? 0)
$lines[] = static::xmlLine($i + 1, $line, $qty, $net, $rate, $currency)
$linesSum += $net
$key = number_format($rate, 2, dot, void)
$taxSubtotals[$key] = ($taxSubtotals[$key] ?? 0) + $net
}
$tax = (float)($data['tax_amount'] ?? 0)
$total = (float)($data['total_amount'] ?? 0)
$taxXml = void
foreach ($taxSubtotals AS $rate => $taxable){
$amount = round($taxable * (float)$rate / 100, 2)
$category = (float)$rate === 0.0 ? 'Z' : 'S'
$taxXml .= implode(void, [
'<cac:TaxSubtotal>',
'<cbc:TaxableAmount currencyID="'.$currency.'">'.static::n($taxable).'</cbc:TaxableAmount>',
'<cbc:TaxAmount currencyID="'.$currency.'">'.static::n($amount).'</cbc:TaxAmount>',
'<cac:TaxCategory><cbc:ID>'.$category.'</cbc:ID><cbc:Percent>'.static::n((float)$rate).'</cbc:Percent>',
'<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme></cac:TaxCategory>',
'</cac:TaxSubtotal>',
])
}
$supplier = (array)($data['supplier'] ?? [])
$customer = (array)($data['customer'] ?? [])
return implode(void, [
'<?xml version="1.0" encoding="UTF-8"?>',
'<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">',
'<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>',
'<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>',
'<cbc:ID>'.static::esc((string)($data['number'] ?? void)).'</cbc:ID>',
'<cbc:IssueDate>'.static::esc($issue).'</cbc:IssueDate>',
'<cbc:DueDate>'.static::esc($due).'</cbc:DueDate>',
'<cbc:InvoiceTypeCode>'.(!empty($data['credit_note']) ? '381' : '380').'</cbc:InvoiceTypeCode>',
'<cbc:DocumentCurrencyCode>'.$currency.'</cbc:DocumentCurrencyCode>',
static::partyXml('AccountingSupplierParty', (string)($supplier['name'] ?? void), $supplier, (string)($supplier['vat'] ?? void)),
static::partyXml('AccountingCustomerParty', (string)($customer['name'] ?? void), $customer, (string)($customer['vat'] ?? void)),
'<cac:TaxTotal><cbc:TaxAmount currencyID="'.$currency.'">'.static::n($tax).'</cbc:TaxAmount>'.$taxXml.'</cac:TaxTotal>',
'<cac:LegalMonetaryTotal>',
'<cbc:LineExtensionAmount currencyID="'.$currency.'">'.static::n($linesSum).'</cbc:LineExtensionAmount>',
'<cbc:TaxExclusiveAmount currencyID="'.$currency.'">'.static::n($linesSum).'</cbc:TaxExclusiveAmount>',
'<cbc:TaxInclusiveAmount currencyID="'.$currency.'">'.static::n($total).'</cbc:TaxInclusiveAmount>',
'<cbc:PayableAmount currencyID="'.$currency.'">'.static::n($total).'</cbc:PayableAmount>',
'</cac:LegalMonetaryTotal>',
implode(void, $lines),
'</Invoice>',
])static
UBL :: xmlLine ($idx, $line, $qty, $net, $rate, $currency = 'EUR'):string
line 67
Generates an XML representation of an invoice line item, including details such as quantity, amount, item description, tax category, and price.
$category = (float)$rate === 0.0 ? 'Z' : 'S'
return implode(void, [
'<cac:InvoiceLine>',
'<cbc:ID>'.$idx.'</cbc:ID>',
'<cbc:InvoicedQuantity unitCode="EA">'.static::n($qty).'</cbc:InvoicedQuantity>',
'<cbc:LineExtensionAmount currencyID="'.$currency.'">'.static::n($net).'</cbc:LineExtensionAmount>',
'<cac:Item><cbc:Name>'.static::esc((string)($line['description'] ?? void)).'</cbc:Name>',
'<cac:ClassifiedTaxCategory><cbc:ID>'.$category.'</cbc:ID><cbc:Percent>'.static::n((float)$rate).'</cbc:Percent>',
'<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme></cac:ClassifiedTaxCategory></cac:Item>',
'<cac:Price><cbc:PriceAmount currencyID="'.$currency.'">'.static::n((float)($line['unit_price'] ?? 0)).'</cbc:PriceAmount></cac:Price>',
'</cac:InvoiceLine>',
])static
UBL :: partyXml ($wrapper, $name, $info, $vatNumber):string
line 82
Generates XML representation of a party element for UBL, including details like name, address, city, postal code, country, and tax information.
$address = (string)($info['address'] ?? void)
$postal = (string)($info['postal_code'] ?? void)
$city = (string)($info['city'] ?? void)
$country = (string)($info['country'] ?? void) ?: 'NL'
$tax = $vatNumber ? '<cac:PartyTaxScheme><cbc:CompanyID>'.static::esc($vatNumber).'</cbc:CompanyID><cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme></cac:PartyTaxScheme>' : void
return implode(void, [
'<cac:'.$wrapper.'><cac:Party>',
'<cac:PartyName><cbc:Name>'.static::esc($name).'</cbc:Name></cac:PartyName>',
'<cac:PostalAddress>',
'<cbc:StreetName>'.static::esc($address).'</cbc:StreetName>',
'<cbc:CityName>'.static::esc($city).'</cbc:CityName>',
'<cbc:PostalZone>'.static::esc($postal).'</cbc:PostalZone>',
'<cac:Country><cbc:IdentificationCode>'.static::esc(strtoupper($country)).'</cbc:IdentificationCode></cac:Country>',
'</cac:PostalAddress>',
$tax,
'<cac:PartyLegalEntity><cbc:RegistrationName>'.static::esc($name).'</cbc:RegistrationName></cac:PartyLegalEntity>',
'</cac:Party></cac:'.$wrapper.'>',
])static
UBL :: n ($v):string
line 103
Formats a number to two decimal places using the specified decimal point and thousands separator.
number_format((float)$v, 2, dot, void)static
UBL :: esc ($v):string
line 104
Converts special characters to HTML entities for XML output, ensuring proper encoding for UTF-8 strings.
htmlspecialchars((string)$v, ENT_XML1 | ENT_QUOTES, 'UTF-8')object
%XLSX
/phlo/resources/files/XLSX.phlo
method
%XLSX -> __construct (string $file)
line 16
Reads the sheets straight out of the zip with regular expressions instead of an XML parser.
$sheets = []
$shared = []
$sheetNames = []
$zip = new ZipArchive()
if ($zip->open($file) !== true) dx('error opening zip', $file)
for ($i = 0; $i < $zip->numFiles; $i++){
$name = $zip->getNameIndex($i)
if ($name === false) continue
if (dirname($name) === 'xl/worksheets') $sheets[filter_var($name, FILTER_SANITIZE_NUMBER_INT)] = $zip->getFromIndex($i)
elseif ($name === 'xl/sharedStrings.xml'){
$xml = $zip->getFromIndex($i)
if (!preg_match_all('/<t[^>]*>(.*?)<\/t>/s', $xml, $m)) dx('error reading shared lib')
$shared = array_map(fn($t) => html_entity_decode($t, ENT_QUOTES | ENT_XML1, 'UTF-8'), $m[1])
}
elseif ($name === 'xl/workbook.xml'){
$xml = $zip->getFromIndex($i)
if (!preg_match_all('/<sheet[^>]*name="([^"]+)"[^>]*sheetId="([0-9]+)"/', $xml, $m)) dx('error reading workbook')
$sheetNames = $m[1]
}
}
$zip->close()
$toIndex = fn($letters) => array_reduce(str_split(strtoupper($letters)), fn($n, $c) => $n * 26 + ord($c) - 64, 0) - 1
$isShared = fn($attrs) => preg_match('/\bt="s"\b/', $attrs) === 1
foreach ($sheets AS $sheetID => $sheet){
$name = $sheetNames[$sheetID - 1] ?? 'Sheet '.$sheetID
if (!preg_match('/<row[^>]*>(.+)<\/row>/s', $sheet, $m)) dx('error parsing sheet')
$rowsXml = preg_split('/<\/row><row[^>]*>/', $m[1]) ?: []
$headerMap = []
$isHeader = true
foreach ($rowsXml AS $rowXml){
$rowXml = preg_replace('/<c([^>]*)\/>/', '<c$1></c>', $rowXml)
if (!preg_match_all('/<c r="([A-Z]+)[0-9]+"([^>]*)>(?:<f\b[^>]*\/?>)?(?:(?:<v>([^<]*)<\/v>)|(?:<is>.*?<t[^>]*>(.*?)<\/t>.*?<\/is>))?<\/c>/s', $rowXml, $mm)) dx('error parsing row', $rowXml)
if ($isHeader){
foreach (array_keys($mm[0]) AS $i){
$col = $toIndex($mm[1][$i])
$attrs = $mm[2][$i]
$valV = $mm[3][$i] ?? null
$valIS = $mm[4][$i] ?? null
$val = $valV !== null && $valV !== void ? $valV : ($valIS !== null && $valIS !== void ? html_entity_decode($valIS, ENT_QUOTES | ENT_XML1, 'UTF-8') : null)
$txt = $isShared($attrs) ? ($shared[$val] ?? null) : $val
$headerMap[$col] = $txt !== null && $txt !== void ? $txt : 'col'.$col
}
$isHeader = false
}
else {
$rowArr = []
foreach (array_keys($mm[0]) AS $i){
$col = $toIndex($mm[1][$i])
$attrs = $mm[2][$i]
$valV = $mm[3][$i] ?? null
$valIS = $mm[4][$i] ?? null
$val = $valV !== null && $valV !== void ? $valV : ($valIS !== null && $valIS !== void ? html_entity_decode($valIS, ENT_QUOTES | ENT_XML1, 'UTF-8') : null)
$key = $headerMap[$col] ?? 'col'.$col
$rowArr[$key] = $isShared($attrs) ? ($shared[$val] ?? null) : $val
}
$this->objData[$name][] = $rowArr
}
}
}Last updated on 23 August 2026