Passed
Push — master ( f6c984...b2c1a8 )
by Eugene
03:35
created

fillResourceSpecialFields()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 1
ccs 0
cts 0
cp 0
nc 1
1
<?php
2
namespace Staticus\Resources\Middlewares;
3
4
use Staticus\Config\ConfigInterface;
5
use Staticus\Diactoros\Response\ResourceDoResponse;
6
use Staticus\Middlewares\MiddlewareAbstract;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Staticus\Exceptions\WrongRequestException;
10
use Staticus\Resources\ResourceDOInterface;
11
use Zend\Diactoros\Response\EmptyResponse;
12
13
abstract class PrepareResourceMiddlewareAbstract extends MiddlewareAbstract
14
{
15
    protected $resourceDO;
16
    /**
17
     * @var ConfigInterface
18
     */
19
    protected $config;
20
21
    public function __construct(ResourceDOInterface $resourceDO, ConfigInterface $config)
22
    {
23
        $this->resourceDO = $resourceDO;
24
        $this->config = $config;
25
    }
26
27
    public function __invoke(
28
        ServerRequestInterface $request,
29
        ResponseInterface $response,
30
        callable $next = null
31
    )
32
    {
33
        parent::__invoke($request, $response, $next);
34
        if (!$this->fillResource()) {
35
36
            return new EmptyResponse(404, $response->getHeaders());
37
        }
38
39
        // Pass the resource to the next middleware
40
        $response = new ResourceDoResponse($this->resourceDO, $response->getStatusCode(), $response->getHeaders());
41
42
        return $next($request, $response);
43
    }
44
45
    /**
46
     * Bugfix for the russian letters
47
     * @param $file
48
     * @return mixed
49
     */
50
    protected function mb_basename($file)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
51
    {
52
        return end(explode('/', $file));
0 ignored issues
show
Bug introduced by
explode('/', $file) cannot be passed to end() as the parameter $array expects a reference.
Loading history...
53
    }
54
55
    /**
56
     * @throws WrongRequestException
57
     * @todo: Write separate cleanup rules for each parameter
58
     */
59
    protected function fillResource()
60
    {
61
        $name = static::getParamFromRequest('name', $this->request);
62
        $name = $this->cleanup($name);
63
        $namespace = dirname($name);
64
        $name = $this->mb_basename($name);
65
        $name = $this->defaultValidator('name', $name, false
66
            , ResourceDOInterface::NAME_REG_SYMBOLS, $this->config->get('staticus.clean_resource_name'));
67
        $namespace = $this->defaultValidator('namespace', $namespace, true
68
            , ResourceDOInterface::NAMESPACE_REG_SYMBOLS, $this->config->get('staticus.clean_resource_name'));
69
        if (!$this->namespaceValidator($namespace)) {
70
71
            return false;
72
        }
73
        $alt = static::getParamFromRequest('alt', $this->request);
74
        $alt = $this->cleanup($alt);
75
        $var = static::getParamFromRequest('var', $this->request);
76
        $var = $this->cleanup($var);
77
        $var = $this->defaultValidator('var', $var, true, ResourceDOInterface::VARIANT_REG_SYMBOLS);
78
        $v = (int)static::getParamFromRequest('v', $this->request);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $v. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
79
        $author = static::getParamFromRequest('author', $this->request);
80
        $author = $this->cleanup($author);
81
82
        $dataDir = $this->config->get('staticus.data_dir');
83
        /**
84
         * You shouldn't check 'recreate' and 'destroy' params here.
85
         * @see \Staticus\Action\StaticMiddlewareAbstract::postAction
86
         * @see \Staticus\Action\StaticMiddlewareAbstract::deleteAction
87
         */
88
        $this->resourceDO
89
            ->reset()
90
            ->setBaseDirectory($dataDir)
91
            ->setNamespace($namespace)
92
            ->setName($name)
93
            ->setNameAlternative($alt)
94
            ->setVariant($var)
95
            ->setVersion($v)
96
            ->setAuthor($author);
97
        if (!$this->resourceDO->getType()) {
98
            $type = static::getParamFromRequest('type', $this->request);
99
            $type = $this->cleanup($type);
100
            $type = $this->defaultValidator('type', $type);
101
            $this->resourceDO->setType($type);
102
        }
103
        $this->fillResourceSpecialFields();
104
105
        return true;
106
    }
107
    abstract protected function fillResourceSpecialFields();
108
109
    protected function cleanup($name)
110
    {
111
        $name = preg_replace('/\s+/u', ' ', trim(mb_strtolower(rawurldecode((string)$name), 'UTF-8')));
112
        $name = str_replace(['\\'], '', $name);
113
114
        return $name;
115
    }
116
117
    /**
118
     * @param $name
119
     * @param ServerRequestInterface $request
120
     * @return string
121
     * @todo move this method somethere
122
     */
123
    public static function getParamFromRequest($name, ServerRequestInterface $request)
124
    {
125
        $attribute = $request->getAttribute($name);
126
        if ($attribute) {
127
128
            return $attribute;
129
        }
130
        $paramsGET = $request->getQueryParams();
131
        $paramsPOST = (array)$request->getParsedBody();
132
133
        $str = isset($paramsPOST[$name])
134
            ? $paramsPOST[$name]
135
            : (
136
                isset($paramsGET[$name])
137
                ? $paramsGET[$name]
138
                : ''
139
            );
140
141
        return $str;
142
    }
143
144
    protected function defaultValidator(
145
        $name, $value, $canBeEmpty = false, $allowedRegexpSymbols = '\w\d\-_', $replaceDeniedSymbols = false)
146
    {
147
        if (!empty($value)) {
148
            if ($replaceDeniedSymbols) {
149
                $value = preg_replace('/\s+/u', ' ', preg_replace('/[^' . $allowedRegexpSymbols . ']+/ui', '', $value));
150
                $value = trim(preg_replace('/\/+/u', '/', $value));
151
            } else {
152
                if (!preg_match('/^[' . $allowedRegexpSymbols . ']+$/ui', $value)) {
153
                    throw new WrongRequestException('Wrong request param "' . $name . '": ' . $value);
154
                }
155
            }
156
        }
157
        if (empty($value) && !$canBeEmpty) {
158
            throw new WrongRequestException('Empty request param "' . $name . '"');
159
        }
160
161
        return $value;
162
    }
163
164
    protected function namespaceValidator($namespace)
165
    {
166
        $allowed = $this->config->get('staticus.namespaces');
167
        if ($namespace && !in_array($namespace, $allowed, true)) {
168
            foreach ($allowed as $item) {
169
                if (false !== strpos($item, '*') && fnmatch($item, $namespace)) {
170
                    // TODO: limitations for nested namespaces
171
172
                    return true;
173
                }
174
            }
175
176
            return false;
177
        }
178
179
        return true;
180
    }
181
}
182