1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\HttpKernel\Debug; 13 14use Symfony\Component\HttpFoundation\Request; 15use Symfony\Component\HttpFoundation\RequestStack; 16use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 17 18/** 19 * Formats debug file links. 20 * 21 * @author Jérémy Romey <jeremy@free-agent.fr> 22 * 23 * @final 24 */ 25class FileLinkFormatter 26{ 27 private $fileLinkFormat; 28 private $requestStack; 29 private $baseDir; 30 private $urlFormat; 31 32 /** 33 * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand 34 */ 35 public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null) 36 { 37 $fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); 38 if ($fileLinkFormat && !\is_array($fileLinkFormat)) { 39 $i = strpos($f = $fileLinkFormat, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); 40 $fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE); 41 } 42 43 $this->fileLinkFormat = $fileLinkFormat; 44 $this->requestStack = $requestStack; 45 $this->baseDir = $baseDir; 46 $this->urlFormat = $urlFormat; 47 } 48 49 public function format(string $file, int $line) 50 { 51 if ($fmt = $this->getFileLinkFormat()) { 52 for ($i = 1; isset($fmt[$i]); ++$i) { 53 if (0 === strpos($file, $k = $fmt[$i++])) { 54 $file = substr_replace($file, $fmt[$i], 0, \strlen($k)); 55 break; 56 } 57 } 58 59 return strtr($fmt[0], ['%f' => $file, '%l' => $line]); 60 } 61 62 return false; 63 } 64 65 /** 66 * @internal 67 */ 68 public function __sleep(): array 69 { 70 $this->fileLinkFormat = $this->getFileLinkFormat(); 71 72 return ['fileLinkFormat']; 73 } 74 75 /** 76 * @internal 77 */ 78 public static function generateUrlFormat(UrlGeneratorInterface $router, string $routeName, string $queryString): ?string 79 { 80 try { 81 return $router->generate($routeName).$queryString; 82 } catch (\Throwable $e) { 83 return null; 84 } 85 } 86 87 private function getFileLinkFormat() 88 { 89 if ($this->fileLinkFormat) { 90 return $this->fileLinkFormat; 91 } 92 93 if ($this->requestStack && $this->baseDir && $this->urlFormat) { 94 $request = $this->requestStack->getMasterRequest(); 95 96 if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { 97 return [ 98 $request->getSchemeAndHttpHost().$this->urlFormat, 99 $this->baseDir.\DIRECTORY_SEPARATOR, '', 100 ]; 101 } 102 } 103 104 return null; 105 } 106} 107