Completed
Push — master ( 1fd9bf...1ba521 )
by Mihail
04:08
created

NativeGenerator::encode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
3
namespace Ffcms\Core\Helper\HTML\System;
4
5
use Ffcms\Core\App;
6
use Ffcms\Core\Helper\Type\Obj;
7
use Ffcms\Core\Helper\Type\Str;
8
use Ffcms\Core\Helper\Url;
9
10
abstract class NativeGenerator
11
{
12
13
    /**
14
     * Make data "safe" - all dangerous html/js/etc will be removed
15
     * @param string $data
16
     * @param bool $quotes
17
     * @return string
18
     */
19
    public static function safe($data, $quotes = false)
20
    {
21
        $purifier = null;
0 ignored issues
show
Unused Code introduced by
$purifier is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
22
        if (App::$Memory->get('object.purifier.helpers') !== null) {
23
            $purifier = App::$Memory->get('object.purifier.helpers');
24
        } else {
25
            $config = \HTMLPurifier_Config::createDefault();
26
            $config->set('Cache.SerializerPath', root . '/Private/Cache/HTMLPurifier/');
27
            $config->set('AutoFormat.AutoParagraph', false);
28
29
            // allow use target=_blank for links
30
            $def = $config->getHTMLDefinition(true);
31
            $def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top');
32
33
            $purifier = new \HTMLPurifier($config);
34
            App::$Memory->set('object.purifier.helpers', $purifier);
35
        }
36
37
        $data = $purifier->purify($data);
38
        return $quotes ? $data : App::$Security->escapeQuotes($data);
39
    }
40
41
    /**
42
     * Remove all html tags from data
43
     * @param string $data
44
     * @param bool $quotes
45
     * @return string
46
     */
47
    public static function nohtml($data, $quotes = false)
48
    {
49
        $plaintext = App::$Security->strip_tags($data);
50
        return $quotes === true ? $plaintext : App::$Security->escapeQuotes($plaintext);
0 ignored issues
show
Bug introduced by
It seems like $plaintext defined by \Ffcms\Core\App::$Security->strip_tags($data) on line 49 can also be of type array; however, Ffcms\Core\Helper\Security::escapeQuotes() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
51
    }
52
53
    /**
54
     * Build property for html element from array.
55
     * IMPORTANT: $property can be null-string (some times this happend's) - do not remove NULL!!
56
     * @param array $property
57
     * @return null|string
58
     */
59
    public static function applyProperty(array $property = null)
60
    {
61
        if (!Obj::isArray($property) || count($property) < 1) {
62
            return null;
63
        }
64
        
65
        $build = null;
66
        foreach ($property as $p => $v) {
0 ignored issues
show
Bug introduced by
The expression $property of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
67
            if ($v === null || $v === false || $v === true) {
68
                $build .= ' ' . self::nohtml($p);
69
            } else {
70
                $build .= ' ' . self::nohtml($p) . '="' . self::nohtml($v) . '"';
71
            }
72
        }
73
        return $build;
74
    }
75
76
    /**
77
     * Fast building single tag based on property's array
78
     * @param string $tagName
79
     * @param array|null $property
80
     * @param bool $closeSlash
81
     * @return string
82
     */
83
    public static function buildSingleTag($tagName, array $property = null, $closeSlash = true)
84
    {
85
        return '<' . self::nohtml($tagName) . self::applyProperty($property) . ($closeSlash ? '/>' : '>');
86
    }
87
88
    /**
89
     * Fast building container type tag based on property's and value
90
     * @param string $tagName
91
     * @param array|null $property
92
     * @param null|string $value
93
     * @param bool $valueHtml
94
     * @return string
95
     */
96
    public static function buildContainerTag($tagName, array $property = null, $value = null, $valueHtml = false)
97
    {
98
        $tagName = self::nohtml($tagName);
99
        if ($valueHtml !== true) {
100
            $value = self::nohtml($value);
101
        }
102
        
103
        return '<' . $tagName . self::applyProperty($property) . '>' . $value . '</' . $tagName . '>';
104
    }
105
106
    /**
107
     * Make parts of URI safe and usable
108
     * @param string $string
109
     * @param bool $encode
110
     * @return string
111
     */
112
    public static function safeUri($string, $encode = true)
113
    {
114
        $string = Str::lowerCase($string);
115
        $string = self::nohtml($string);
116
        if ($encode === true) {
117
            $string = self::encode($string);
118
        }
119
        return $string;
120
    }
121
122
    /**
123
     * Check if uri $source is equal to current uri point with array of $aliases and active $order set
124
     * @param null $source
125
     * @param array|null $aliases
126
     * @param bool $order
127
     * @return bool
128
     */
129
    public static function isCurrentLink($source = null, array $aliases = null, $order = false)
130
    {
131
        $elementPoint = Url::buildPathway($source);
132
        $currentPoint = Url::buildPathwayFromRequest();
133
134
        // use special active element order type: controller, action
135
        switch ($order) {
136
            case 'controller':
137
                $elementPoint = Str::firstIn($elementPoint, '/');
138
                $active = Str::startsWith($elementPoint, $currentPoint);
0 ignored issues
show
Security Bug introduced by
It seems like $elementPoint defined by \Ffcms\Core\Helper\Type\...tIn($elementPoint, '/') on line 137 can also be of type false; however, Ffcms\Core\Helper\Type\Str::startsWith() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
139
                break;
140
            case 'action':
141
                $elementArray = explode('/', $elementPoint);
142
                if (!Str::contains('/', $elementPoint) || count($elementArray) < 2) {
143
                    $active = $elementPoint === $currentPoint;
144
                } else {
145
                    $elementPoint = $elementArray[0] . '/' . $elementArray[1];
146
                    $active = Str::startsWith($elementPoint, $currentPoint);
147
                }
148
                break;
149
            case 'id':
150
                $elementArray = explode('/', $elementPoint);
151
                $elementPoint = $elementArray[0] . '/' . $elementArray[1];
152
                if ($elementArray[2] === null) { // looks like id is not defined in element
153
                    if (Str::contains('?', $currentPoint)) {
154
                        $currentPoint = Str::firstIn($currentPoint, '?');
155
                    }
156
                    $currentArray = explode('/', $currentPoint);
157
                    $currentToId = implode('/', array_slice($currentArray, 0, 3));
158
                    $active = $elementPoint === $currentToId;
159
                } else {
160
                    $elementPoint .= '/' . $elementArray[2];
161
                    $active = Str::startsWith($elementPoint, $currentPoint);
162
                }
163
                break;
164
            default:
165
                $active = $elementPoint === $currentPoint;
166
                break;
167
        }
168
169
        // check if current uri equals with aliases
170
        if (Obj::isArray($aliases) && count($aliases) > 0) {
171
            foreach ($aliases as $activeUri) {
0 ignored issues
show
Bug introduced by
The expression $aliases of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
172
                $activeUri = trim($activeUri, '/');
173
                if (Str::endsWith('*', $activeUri)) {
174
                    $activeUri = rtrim($activeUri, '*');
175
                    if (Str::startsWith($activeUri, $currentPoint)) {
0 ignored issues
show
Bug introduced by
It seems like $currentPoint can also be of type false or null; however, Ffcms\Core\Helper\Type\Str::startsWith() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
176
                        $active = true;
177
                    }
178
                } else {
179
                    if ($activeUri === $currentPoint) {
180
                        $active = true;
181
                    }
182
                }
183
            }
184
        }
185
186
        return $active;
187
    }
188
189
    /**
190
     * Apply security for string to output as html
191
     * @param string|null $object
192
     * @param bool $html
193
     * @param bool $secure
194
     * @return null|string
195
     */
196
    public static function applyEscape($object = null, $html = false, $secure = false)
197
    {
198
        $object = (string)$object;
199
        if ($html !== true) {
200
            $object = self::nohtml($object);
201
        } elseif ($secure !== true) {
202
            $object = self::safe($object, true);
203
        }
204
205
        return $object;
206
    }
207
208
    /**
209
     * Convert link-binding type to classic link with security filter
210
     * @param string|array $uri
211
     * @return string
212
     */
213
    public static function convertLink($uri)
214
    {
215
        $link = App::$Alias->baseUrl . '/';
216
        if (Obj::isArray($uri)) {
217
            $link .= Url::buildPathway($uri);
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 213 can also be of type string; however, Ffcms\Core\Helper\Url::buildPathway() does only seem to accept null|array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
218
        } elseif (Str::startsWith('http', $uri)) {
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 213 can also be of type array; however, Ffcms\Core\Helper\Type\Str::startsWith() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
219
            $link = self::nohtml($uri);
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 213 can also be of type array; however, Ffcms\Core\Helper\HTML\S...tiveGenerator::nohtml() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
220
        } elseif (Str::startsWith('#', $uri)) { // allow pass #part
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 213 can also be of type array; however, Ffcms\Core\Helper\Type\Str::startsWith() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
221
            $link = self::nohtml($uri);
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 213 can also be of type array; however, Ffcms\Core\Helper\HTML\S...tiveGenerator::nohtml() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
222
        } else {
223
            $link .= self::nohtml(trim($uri, '/'));
224
        }
225
        return $link;
226
    }
227
228
    /**
229
     * Encode safe uri links with slashes
230
     * @param $uri
231
     * @return string
232
     */
233
    public static function encode($uri)
234
    {
235
        return implode('/', array_map(function($v){
236
            return urlencode($v);
237
        }, explode('/', $uri)));
238
    }
239
240
241
}