These five helpers cover diagnostic logging, byte sizes, elapsed time, Turkish-text slugs and date formatting. They use PHP 8.x syntax; the slug helper requires mbstring. Check for existing function names before copying them into an application. They are examples, not a complete error-management or routing system.
Keep diagnostic details out of the response
In production, use server-side logging rather than printing paths and error text to visitors. Configure display_errors off and log_errors on. This handler deliberately records only the diagnostic level and location, not the raw message.
<?php
set_error_handler(function (int $no, string $message, string $file, int $line): bool {
if (!(error_reporting() & $no)) {
return false;
}
error_log(sprintf('PHP diagnostic [%d] at %s:%d', $no, $file, $line));
return true;
});
set_error_handler cannot handle every fatal error and does not replace catching Throwable. Returning true bypasses the default handler for that diagnostic, so logging and any additional behavior become your responsibility. Restrict access to logs; if you add message text, redact secrets and personal data.
Format bytes with binary units
<?php
function boyut(int $bayt): string {
if ($bayt < 0) {
throw new InvalidArgumentException('Negative byte count');
}
$units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];
$value = (float) $bayt;
$i = 0;
while ($value >= 1024 && $i < count($units) - 1) {
$value /= 1024;
$i++;
}
return ($i === 0 ? (string) $bayt : number_format($value, 2, '.', ''))
. ' ' . $units[$i];
}
echo boyut(1024); // 1.00 KiB
Dividing by 1024 calls for KiB/MiB-style units. The original small-value branch returned a literal string instead of the actual count; this version handles zero and 1023 bytes. Negative input is rejected. Supply bytes, not bits, and validate untrusted form values before calling the function.
Round elapsed durations down
<?php
function gecenSure(int $zaman, ?int $simdi = null): string {
$fark = ($simdi ?? time()) - $zaman;
if ($fark < 0) {
throw new InvalidArgumentException('Future timestamp');
}
foreach ([86400 => 'days', 3600 => 'hours', 60 => 'minutes', 1 => 'seconds'] as $scale => $unit) {
if ($fark >= $scale || $scale === 1) {
return intdiv($fark, $scale) . ' ' . $unit . ' ago';
}
}
}
echo gecenSure(1000, 1125); // 2 minutes ago
The input is a Unix timestamp. The optional reference time makes tests deterministic; omitting it uses time(). This is an approximate duration derived from seconds, not calendar-month or calendar-year arithmetic. Future input is rejected rather than displayed as a negative “ago” value. Unit labels are deliberately simple; a localized interface should handle singular and plural forms.
Generate a bounded slug from Turkish text
<?php
function seoyap(string $text): string {
$text = strtr($text, ['İ'=>'i', 'I'=>'i', 'ı'=>'i', 'Ç'=>'c', 'ç'=>'c',
'Ğ'=>'g', 'ğ'=>'g', 'Ö'=>'o', 'ö'=>'o', 'Ş'=>'s', 'ş'=>'s', 'Ü'=>'u', 'ü'=>'u']);
$text = mb_strtolower($text, 'UTF-8');
$text = trim(preg_replace('/[^a-z0-9]+/', '-', $text), '-');
if ($text === '' || strlen($text) > 160) {
throw new InvalidArgumentException('Invalid slug length');
}
return $text;
}
echo seoyap('İçerik Yönetimi'); // icerik-yonetimi
This handles Turkish characters, not transliteration for every writing system. Empty results and slugs longer than 160 characters are rejected. Different titles can still produce the same slug, so enforce uniqueness in the database. Do not regenerate existing URLs in bulk without planning redirects.
Validate a date before reformatting it
<?php
function tarihcevir(string $tarih): string {
if (!preg_match('~^\d{4}/\d{2}/\d{2}$~D', $tarih)) {
throw new InvalidArgumentException('Expected YYYY/MM/DD');
}
$date = DateTimeImmutable::createFromFormat('!Y/m/d', $tarih, new DateTimeZone('UTC'));
$errors = DateTimeImmutable::getLastErrors();
if (!$date || ($errors !== false && ($errors['warning_count'] || $errors['error_count']))
|| $date->format('Y/m/d') !== $tarih) {
throw new InvalidArgumentException('Invalid calendar date');
}
return $date->format('d-m-Y');
}
echo tarihcevir('2018/09/13'); // 13-09-2018
The accepted input is exactly YYYY/MM/DD. An impossible date such as 2026/02/31 must not roll into the next month unnoticed. The function checks createFromFormat diagnostics and the getLastErrors result, including false when parsing produced no warnings or errors.
Test zero bytes, negative input, future timestamps, punctuation-only titles and invalid calendar dates. A useful helper needs a defined response to unexpected input as well as a working happy path.