Example:setPath("somefolder","otherfolder"); * * @param null|string|string[] $templatePath If null then it uses the current path /views folder * @param null|string $compiledPath If null then it uses the current path /views folder */ public function setPath($templatePath, $compiledPath): void { if ($templatePath === null) { $templatePath = \getcwd() . '/views'; } if ($compiledPath === null) { $compiledPath = \getcwd() . '/compiles'; } $this->templatePath = (is_array($templatePath)) ? $templatePath : [$templatePath]; $this->compiledPath = $compiledPath; } /** * @return array */ public function getAliasClasses(): array { return $this->aliasClasses; } /** * @param array $aliasClasses */ public function setAliasClasses($aliasClasses): void { $this->aliasClasses = $aliasClasses; } /** * @param string $aliasName * @param string $classWithNS */ public function addAliasClasses($aliasName, $classWithNS): void { $this->aliasClasses[$aliasName] = $classWithNS; } //
Example: getTemplateFile('.abc.def')
* * @param string $templateName template name. If not template is set then it uses the base template. * @return string */ public function getTemplateFile($templateName = ''): string { $templateName = (empty($templateName)) ? $this->fileName : $templateName; if (\strpos($templateName, '/') !== false) { return $this->locateTemplate($templateName); // it's a literal } $arr = \explode('.', $templateName); $c = \count($arr); if ($c == 1) { // it's in the root of the template folder. return $this->locateTemplate($templateName . $this->fileExtension); } $file = $arr[$c - 1]; \array_splice($arr, $c - 1, $c - 1); // delete the last element $path = \implode('/', $arr); return $this->locateTemplate($path . '/' . $file . $this->fileExtension); } /** * Find template file with the given name in all template paths in the order the paths were written * * @param string $name Filename of the template (without path) * @return string template file */ protected function locateTemplate($name): string { $this->notFoundPath = ''; foreach ($this->templatePath as $dir) { $path = $dir . '/' . $name; if (\is_file($path)) { return $path; } $this->notFoundPath .= $path . ","; } return ''; } /** * Get the contents of a file. * * @param string $fullFileName It gets the content of a filename or returns ''. * * @return string */ public function getFile($fullFileName): string { if (\is_file($fullFileName)) { return \file_get_contents($fullFileName); } $this->showError('getFile', "File does not exist at paths (separated by comma) [$this->notFoundPath] or permission denied"); return ''; } protected function compileCallBacks(&$contents, $templateName): void { if (!empty($this->compileCallbacks)) { foreach ($this->compileCallbacks as $callback) { if (is_callable($callback)) { $callback($contents, $templateName); } } } } /** * Determine if the view has expired. * * @param string|null $fileName * @return bool */ public function isExpired($fileName): bool { $compiled = $this->getCompiledFile($fileName); $template = $this->getTemplateFile($fileName); if (!\is_file($template)) { if ($this->mode == self::MODE_DEBUG) { $this->showError('Read file', 'Template not found :' . $this->fileName . " on file: $template", true); } else { $this->showError('Read file', 'Template not found :' . $this->fileName, true); } } // If the compiled file doesn't exist we will indicate that the view is expired // so that it can be re-compiled. Else, we will verify the last modification // of the views is less than the modification times of the compiled views. if (!$this->compiledPath || !\is_file($compiled)) { return true; } return \filemtime($compiled) < \filemtime($template); } /** * Evaluates a text (string) using the current variables * * @param string $content * @param array $variables * @return string * @throws Exception */ protected function evaluateText($content, $variables): string { \ob_start(); \extract($variables); // We'll evaluate the contents of the view inside a try/catch block, so we can // flush out any stray output that might get out before an error occurs or // an exception is thrown. This prevents any partial views from leaking. try { eval(' ?>' . $content . $this->phpTag); } catch (\Throwable $e) { $this->handleViewException($e); } return \ltrim(\ob_get_clean()); } /** * Handle a view exception. * * @param Exception $e * @return void * @throws $e */ protected function handleViewException($e): void { \ob_get_clean(); throw $e; } /** * Evaluates a compiled file using the current variables * * @param string $compiledFile full path of the compile file. * @param array $variables * @return string * @throws Exception */ protected function evaluatePath($compiledFile, $variables): string { \ob_start(); // note, the variables are extracted locally inside this method, // they are not global variables :-3 \extract($variables); // We'll evaluate the contents of the view inside a try/catch block, so we can // flush out any stray output that might get out before an error occurs or // an exception is thrown. This prevents any partial views from leaking. try { include $compiledFile; } catch (\Throwable $e) { $this->handleViewException($e); } return \ltrim(\ob_get_clean()); } /** * @param array $views array of views * @param array $value * @return string * @throws Exception */ public function includeFirst($views = [], $value = []): string { foreach ($views as $view) { if ($this->templateExist($view)) { return $this->runChild($view, $value); } } return ''; } /** * Returns true if the template exists. Otherwise, it returns false * * @param $templateName * @return bool */ protected function templateExist($templateName): bool { $file = $this->getTemplateFile($templateName); return \is_file($file); } /** * Convert an array such as ["class1"=>"myclass","style="mystyle"] to class1='myclass' style='mystyle' string * * @param array|string $array array to convert * @return string */ public function convertArg($array): string { if (!\is_array($array)) { return $array; // nothing to convert. } return \implode(' ', \array_map('BladeOne::convertArgCallBack', \array_keys($array), $array)); } /** * Returns the current token. if there is not a token then it generates a new one. * It could require an open session. * * @param bool $fullToken It returns a token with the current ip. * @param string $tokenId [optional] Name of the token. * * @return string */ public function getCsrfToken($fullToken = false, $tokenId = '_token'): string { if ($this->csrf_token == '') { $this->regenerateToken($tokenId); } if ($fullToken) { return $this->csrf_token . '|' . $this->ipClient(); } return $this->csrf_token; } /** * Regenerates the csrf token and stores in the session. * It requires an open session. * * @param string $tokenId [optional] Name of the token. */ public function regenerateToken($tokenId = '_token'): void { try { $this->csrf_token = \bin2hex(\random_bytes(10)); } catch (\Throwable $e) { $this->csrf_token = '123456789012345678901234567890'; // unable to generates a random token. } @$_SESSION[$tokenId] = $this->csrf_token . '|' . $this->ipClient(); } public function ipClient() { if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) && \preg_match('/^(d{1,3}).(d{1,3}).(d{1,3}).(d{1,3})$/', $_SERVER['HTTP_X_FORWARDED_FOR']) ) { return $_SERVER['HTTP_X_FORWARDED_FOR']; } return $_SERVER['REMOTE_ADDR'] ?? ''; } /** * Validates if the csrf token is valid or not.';
\var_dump($object);
echo '';
} else {
/** @noinspection BadExpressionStatementJS */
/** @noinspection JSVoidFunctionReturnValueUsed */
echo '';
}
}
/**
* Start injecting content into a section.
*
* @param string $section
* @param string $content
* @return void
*/
public function startSection($section, $content = ''): void
{
if ($content === '') {
\ob_start() && $this->sectionStack[] = $section;
} else {
$this->extendSection($section, $content);
}
}
/**
* Stop injecting content into a section and append it.
*
* @return string
* @throws InvalidArgumentException
*/
public function appendSection(): string
{
if (empty($this->sectionStack)) {
$this->showError('appendSection', 'Cannot end a section without first starting one.', true, true);
}
$last = \array_pop($this->sectionStack);
if (isset($this->sections[$last])) {
$this->sections[$last] .= \ob_get_clean();
} else {
$this->sections[$last] = \ob_get_clean();
}
return $last;
}
/**
* Adds a global variable. If **$varname** is an array then it merges all the values.
* **Example:**
* ```
* $this->share('variable',10.5);
* $this->share('variable2','hello');
* // or we could add the two variables as:
* $this->share(['variable'=>10.5,'variable2'=>'hello']);
* ```
*
* @param string|array $varname It is the name of the variable or, it is an associative array
* @param mixed $value
* @return $this
* @see BladeOne::share
*/
public function with($varname, $value = null): BladeOne
{
return $this->share($varname, $value);
}
/**
* Adds a global variable. If **$varname** is an array then it merges all the values.
* **Example:**
* ```
* $this->share('variable',10.5);
* $this->share('variable2','hello');
* // or we could add the two variables as:
* $this->share(['variable'=>10.5,'variable2'=>'hello']);
* ```
*
* @param string|array $varname It is the name of the variable, or it is an associative array
* @param mixed $value
* @return $this
*/
public function share($varname, $value = null): BladeOne
{
if (is_array($varname)) {
$this->variablesGlobal = \array_merge($this->variablesGlobal, $varname);
} else {
$this->variablesGlobal[$varname] = $value;
}
return $this;
}
/**
* Get the string contents of a section.
*
* @param string $section
* @param string $default
* @return string
*/
public function yieldContent($section, $default = ''): string
{
if (isset($this->sections[$section])) {
return \str_replace($this->PARENTKEY, $default, $this->sections[$section]);
}
return $default;
}
/**
* Register a custom Blade compiler.
*
* @param callable $compiler
* @return void
*/
public function extend(callable $compiler): void
{
$this->extensions[] = $compiler;
}
/**
* Register a handler for custom directives for run at runtime
*
* @param string $name
* @param callable $handler
* @return void
*/
public function directiveRT($name, callable $handler): void
{
$this->customDirectives[$name] = $handler;
$this->customDirectivesRT[$name] = true;
}
/**
* Sets the escaped content tags used for the compiler.
*
* @param string $openTag
* @param string $closeTag
* @return void
*/
public function setEscapedContentTags($openTag, $closeTag): void
{
$this->setContentTags($openTag, $closeTag, true);
}
/**
* Gets the content tags used for the compiler.
*
* @return array
*/
public function getContentTags(): array
{
return $this->getTags();
}
/**
* Sets the content tags used for the compiler.
*
* @param string $openTag
* @param string $closeTag
* @param bool $escaped
* @return void
*/
public function setContentTags($openTag, $closeTag, $escaped = false): void
{
$property = ($escaped === true) ? 'escapedTags' : 'contentTags';
$this->{$property} = [\preg_quote($openTag), \preg_quote($closeTag)];
}
/**
* Gets the tags used for the compiler.
*
* @param bool $escaped
* @return array
*/
protected function getTags($escaped = false): array
{
$tags = $escaped ? $this->escapedTags : $this->contentTags;
return \array_map('stripcslashes', $tags);
}
/**
* Gets the escaped content tags used for the compiler.
*
* @return array
*/
public function getEscapedContentTags(): array
{
return $this->getTags(true);
}
/**
* Sets the function used for resolving classes with inject.
*
* @param callable $function
*/
public function setInjectResolver(callable $function): void
{
$this->injectResolver = $function;
}
/**
* Get the file extension for template files.
*
* @return string
*/
public function getFileExtension(): string
{
return $this->fileExtension;
}
/**
* Set the file extension for the template files.
* It must include the leading dot e.g. ".blade.php"
*
* @param string $fileExtension Example: .prefix.ext
*/
public function setFileExtension($fileExtension): void
{
$this->fileExtension = $fileExtension;
}
/**
* Get the file extension for template files.
*
* @return string
*/
public function getCompiledExtension(): string
{
return $this->compileExtension;
}
/**
* Set the file extension for the compiled files.
* Including the leading dot for the extension is required, e.g. ".bladec"
*
* @param $fileExtension
*/
public function setCompiledExtension($fileExtension): void
{
$this->compileExtension = $fileExtension;
}
/**
* @return string
* @see BladeOne::setCompileTypeFileName
*/
public function getCompileTypeFileName(): string
{
return $this->compileTypeFileName;
}
/**
* It determines how the compiled filename will be called.'; var_dump$expression; echo '';?>"; } /** * Execute the case tag. * * @param $expression * @return string */ protected function compileCase($expression): string { if ($this->firstCaseInSwitch) { $this->firstCaseInSwitch = false; return 'case ' . $expression . ': ?>'; } return $this->phpTag . "case $expression: ?>"; } /** * Compile the while statements into valid PHP. * * @param string $expression * @return string */ protected function compileWhile($expression): string { return $this->phpTag . "while$expression: ?>"; } /** * default tag used for switch/case * * @return string */ protected function compileDefault(): string { if ($this->firstCaseInSwitch) { return $this->showError('@default', '@switch without any @case', true); } return $this->phpTag . 'default: ?>'; } protected function compileEndSwitch(): string { --$this->switchCount; if ($this->switchCount < 0) { return $this->showError('@endswitch', 'Missing @switch', true); } return $this->phpTag . '} // end switch ?>'; } /** * Compile while statements into valid PHP. * * @param string $expression * @return string */ protected function compileInject($expression): string { $ex = $this->stripParentheses($expression); $p0 = \strpos($ex, ','); if (!$p0) { $var = $this->stripQuotes($ex); $namespace = ''; } else { $var = $this->stripQuotes(\substr($ex, 0, $p0)); $namespace = $this->stripQuotes(\substr($ex, $p0 + 1)); } return $this->phpTag . "\$$var = \$this->injectClass('$namespace', '$var'); ?>"; } /** * Remove first and end quote from a quoted string of text * * @param mixed $text * @return null|string|string[] */ public function stripQuotes($text) { if (!$text || strlen($text) < 2) { return $text; } $text = trim($text); $p0 = $text[0]; $p1 = \substr($text, -1); if ($p0 === $p1 && ($p0 === '"' || $p0 === "'")) { return \substr($text, 1, -1); } return $text; } /** * Execute the user defined extensions. * * @param string $value * @return string */ protected function compileExtensions($value): string { foreach ($this->extensions as $compiler) { $value = $compiler($value, $this); } return $value; } /** * Compile Blade comments into valid PHP. * * @param string $value * @return string */ protected function compileComments($value): string { $pattern = "/" . $this->contentTags[0] . "--(.*?)--" . $this->contentTags[1] . "/s"; switch ($this->commentMode) { case 0: return \preg_replace($pattern, $this->phpTag . '/*$1*/ ?>', $value); case 1: return \preg_replace($pattern, '', $value); default: return \preg_replace($pattern, '', $value); } } /** * Compile Blade echos into valid PHP. * * @param string $value * @return string * @throws Exception */ protected function compileEchos($value): string { foreach ($this->getEchoMethods() as $method => $length) { $value = $this->$method($value); } return $value; } /** * Get the echo methods in the proper order for compilation. * * @return array */ protected function getEchoMethods(): array { $methods = [ 'compileRawEchos' => \strlen(\stripcslashes($this->rawTags[0])), 'compileEscapedEchos' => \strlen(\stripcslashes($this->escapedTags[0])), 'compileRegularEchos' => \strlen(\stripcslashes($this->contentTags[0])), ]; \uksort($methods, static function($method1, $method2) use ($methods) { // Ensure the longest tags are processed first if ($methods[$method1] > $methods[$method2]) { return -1; } if ($methods[$method1] < $methods[$method2]) { return 1; } // Otherwise, give preference to raw tags (assuming they've overridden) if ($method1 === 'compileRawEchos') { return -1; } if ($method2 === 'compileRawEchos') { return 1; } if ($method1 === 'compileEscapedEchos') { return -1; } if ($method2 === 'compileEscapedEchos') { return 1; } throw new BadMethodCallException("Method [$method1] not defined"); }); return $methods; } /** * Compile Blade components that start with "x-". * * @param string $value * * @return array|string|string[]|null */ protected function compileComponents($value) { /** * @param array $match * [0]=full expression with @ and parenthesis * [1]=Component name * [2]=parameters * [3]=... * [4]=content * * @return string */ $callback = function($match) { if (static::contains($match[0], 'x-')) { $match[4] = $this->compileComponents($match[4]); } $paramsCompiled = $this->parseParams($match[2]); $str = "('components." . $match[1] . "'," . $paramsCompiled . ")"; return self::compileComponent($str) . $match[4] . self::compileEndComponent(); }; return preg_replace_callback('/