0

这与我之前问过的一个问题有关:Replacing named 'parameters' within a string in PHP

那个小类过去可以工作,但它似乎行为不端,现在我正试图将它移到新的 Bolt CMS 作为扩展。

目的是从 YML 文件中获取数据。数据如下所示:

redirects:
    contentToPage:
        from: "content/(slug:any)"
        to: "page/{slug}"

扩展循环遍历这些数据并将其与从适用的 Symfony 组件获得的当前请求 URI 进行比较。如果匹配,用户将被相应地重定向。因此,在这种情况下,如果用户尝试访问content/test,他们将被重定向到page/test

不过,似乎出了点问题,转换后的替换不正确,或者我得到了一个错误。首先,这是有问题的块:

$convertedReplacements = preg_replace_callback("/^{$convertedPlaceholders}$/", function ($captures) {
    $result = $this->destination;
    for ($c = 1, $n = count($captures); $c < $n; ++$c) {
        $value = array_shift($this->computedReplacements);
        $result = str_replace("\{$value\}", $captures[$c], $result);
    }
    return $result;
}, $requestUri);

$convertedPlaceholders包含值中的替换参数from。所以,(slug:any)将替换为([a-z0-9\.\-\_\%\=]+). 现在,这行得通,但是该函数会引发此异常:preg_replace_callback(): Unknown modifier '('.

但是,如果我将正则表达式分隔符从/to更改为~or #,我不会收到错误消息。相反,我得到了to在 YML 文件中获取属性的值。在这种情况下,我得到page/{slug}而不是page/test.

我一定在做一些愚蠢的事情,我不知道那是什么。据我所知,我只是遗漏了一些我看不到的东西。

这是整个扩展:

<?php
// Redirector Extension for Bolt
// Minimum version: 1.2

namespace Redirector;

use Silex\Application as Application;
use Symfony\Component\HttpFoundation\Request as Request;
use Symfony\Component\Yaml\Parser as Parser;
use Bolt\BaseExtension as BoltExtension;

class Extension extends BoltExtension
{
    protected $placeholders = array(
        ':all' => '.*',
        ':alpha' => '[a-z]+',
        ':alphanum' => '[a-z0-9]+',
        ':any' => '[a-z0-9\.\-\_\%\=]+',
        ':num' => '[0-9]+',
        ':segment' => '[a-z0-9\-\_]+',
        ':segments' => '[a-z0-9\-\_\/]+'
    );

    protected $computedReplacements;

    protected $destination;

    /**
     * Basic information about the extension. Shown in the Bolt Admin Environment.
     *
     * @return Array
     */

    function info() {
        $data = array(
            'name' => 'Redirector',
            'version' => '0.1',
            'author' => 'Foundry Code - Mike Anthony',
            'description' => 'An extension that allows you to perform any pre-app <code>301 Moved Permanently</code> redirects.',
            'type' => 'Pre-app Hook',
            'link' => 'http://code.foundrybusiness.co.za/extensions/bolt-redirector',
            'first_releasedate' => '2013-08-28',
            'latest_releasedate' => '2013-08-28',
            'required_bolt_version' => '1.2',
            'highest_bolt_version' => '1.2'
        );
        return $data;
    }

    /**
     * Initialise the extension's functions
     *
     * @return void
     */

    function initialize() {
        $this->options = $this->config['options'];
        $this->redirects = $this->config['redirects'];
        $this->handleRedirects();
    }

    /**
     * Check for a redirect. If it exists, then redirect to it's computed replacement.
     *
     * @return ? Response
     */
    function handleRedirects()
    {
        $redirector = $this;
        $this->app->before(function (Request $request) use ($redirector) {
            if (empty($redirector->redirects)) {
                return;
            }
            $requestUri = trim($request->getRequestUri(), '/');

            $availablePlaceholders = '';
            foreach ($this->placeholders as $placeholder => $expression) {
                $availablePlaceholders .= ltrim("$placeholder|", ':');
            }
            $availablePlaceholders = rtrim($availablePlaceholders, '|');
            //die($availablePlaceholders);

            $pattern = '/\{(\w+):('.$availablePlaceholders.')\}/';
            //die($pattern);

            foreach ($this->redirects as $redirectName => $redirectData) {
                $this->computedReplacements = array();
                $this->destination = $redirectData['to'];
                $from = rtrim($redirectData['from'], '/');
                $to = rtrim($redirectData['to'], '/');

                $convertedPlaceholders = preg_replace_callback($pattern, function ($captures) {
                    $this->computedReplacements[] = $captures[1];
                    return '(' . $this->placeholders[":{$captures[2]}"] . ')';
                }, $from);
                //die($convertedPlaceholders);

                $convertedReplacements = preg_replace_callback("/^{$convertedPlaceholders}$/", function ($captures) {
                    $result = $this->destination;
                    for ($c = 1, $n = count($captures); $c < $n; ++$c) {
                        $value = array_shift($this->computedReplacements);
                        $result = str_replace("\{$value\}", $captures[$c], $result);
                    }
                    return $result;
                }, $requestUri);
                die($convertedReplacements);

                if (preg_match("~^{$convertedPlaceholders}$~i", $requestUri)) {
                    return $this->app->redirect("/$convertedReplacements", 301);
                }
            }
        }, Application::EARLY_EVENT);
    }
}

关于我可以在这里做什么的任何想法?

4

2 回答 2

0

如果您想/用作正则表达式分隔符,您应该转义/正则表达式中的所有字符,或者更好的是,像您一样使用另一个分隔符。

于 2013-09-08T10:46:25.387 回答
0

对,它现在似乎正在工作。出于某种原因,当我改变时,一切都到位了:

str_replace("\{$value\}", $captures[$c], $result);

str_replace('{' . $value . '}', $captures[$c], $result);

我认为这与逃避有关,这很奇怪。在第一个中,我使用了双引号,并转义了大括号,使其呈现为{slug}. 但是,出于某种原因,这并没有发生。关于为什么的任何想法?

于 2013-09-08T11:07:16.220 回答