Issues (1919)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

lib/Ajde/Component/String.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
class Ajde_Component_String extends Ajde_Component
4
{
5
    protected static $_allowedTags = '<table><tr><td><th><tfoot><tbody><thead><a><br><p><div><ul><li><b><h1><h2><h3><h4><h5><h6><strong><i><em><u><img><span><pre>';
6
7
    public static function processStatic(Ajde_Template_Parser $parser, $attributes)
8
    {
9
        $instance = new self($parser, $attributes);
10
11
        return $instance->process();
12
    }
13
14
    protected function _init()
15
    {
16
        return [
17
            'escape' => 'escape',
18
            'clean'  => 'clean',
19
        ];
20
    }
21
22
    public function process()
23
    {
24
        switch ($this->_attributeParse()) {
25
            case 'escape':
26
                $var = $this->attributes['var'];
27
28
                return $this->escape($var);
29
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
30
            case 'clean':
31
                $var = $this->attributes['var'];
32
33
                return $this->clean($var);
34
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
35
        }
36
        // TODO:
37
        throw new Ajde_Component_Exception();
38
    }
39
40
    public static function escape($var)
41
    {
42
        if (is_array($var)) {
43
            array_walk($var, ['Ajde_Component_String', 'rescape']);
44
45
            return $var;
46
        } else {
47
            return self::_escape($var);
48
        }
49
    }
50
51
    private static function rescape(&$var, $key)
0 ignored issues
show
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
52
    {
53
        if (is_array($var)) {
54
            array_walk($var, ['Ajde_Component_String', 'rescape']);
55
        } else {
56
            $var = htmlspecialchars($var, ENT_QUOTES);
57
        }
58
    }
59
60
    private static function _escape($var)
61
    {
62
        return htmlspecialchars($var, ENT_QUOTES);
63
    }
64
65
    public static function clean($var)
66
    {
67
        $clean = strip_tags($var, self::$_allowedTags);
68
69
        return $clean;
70
    }
71
72
    public static function purify($var)
73
    {
74
        $external = Ajde_Core_ExternalLibs::getInstance();
75
        if ($external->has('HTMLPurifier')) {
76
            $purifier = $external->get('HTMLPurifier');
77
78
            /* @var $purifier HTMLPurifier */
79
80
            $config = HTMLPurifier_Config::createDefault();
81
82
            $config->set('AutoFormat.AutoParagraph', true);
83
            $config->set('AutoFormat.DisplayLinkURI', false);
84
            $config->set('AutoFormat.Linkify', false);
85
            $config->set('AutoFormat.RemoveEmpty', true);
86
            $config->set('AutoFormat.RemoveSpansWithoutAttributes', true);
87
88
            $config->set('CSS.AllowedProperties', '');
89
90
            $config->set('HTML.Doctype', 'XHTML 1.0 Strict');
91
92
            $config->set('URI.DisableExternalResources', true);
93
94
            $purifier->config = HTMLPurifier_Config::create($config);
95
96
            return $purifier->purify($var);
97
        } else {
98
            return self::clean($var);
99
        }
100
    }
101
102
    // http://www.php.net/manual/en/language.types.boolean.php#101180
103
    public static function toBoolean($val, $trueValues = ['yes', 'y', 'true'], $forceLowercase = true)
104
    {
105
        if (is_string($val)) {
106
            return in_array(($forceLowercase ? strtolower($val) : $val), $trueValues);
107
        } else {
108
            return (bool) $val;
109
        }
110
    }
111
112
    public static function makePlural($count, $singular)
113
    {
114
        $count = (int) $count;
115
        $ret = $count.' '.$singular;
116
        if ($count > 1 || $count == 0) {
117
            $ret .= 's';
118
        }
119
120
        return $ret;
121
    }
122
123
    /**
124
     * Validate an email address.
125
     * Provide email address (raw input)
126
     * Returns true if the email address has the email
127
     * address format and the domain exists.
128
     *
129
     * @see http://www.linuxjournal.com/article/9585?page=0,3
130
     *
131
     * @return bool
132
     */
133
    public static function validEmail($email)
134
    {
135
        $isValid = true;
136
        $atIndex = strrpos($email, '@');
137
        if (is_bool($atIndex) && !$atIndex) {
138
            $isValid = false;
139
        } else {
140
            $domain = substr($email, $atIndex + 1);
141
            $local = substr($email, 0, $atIndex);
142
            $localLen = strlen($local);
143
            $domainLen = strlen($domain);
144
            if ($localLen < 1 || $localLen > 64) {
145
                // local part length exceeded
146
                $isValid = false;
147
            } else {
148
                if ($domainLen < 1 || $domainLen > 255) {
149
                    // domain part length exceeded
150
                    $isValid = false;
151
                } else {
152
                    if ($local[0] == '.' || $local[$localLen - 1] == '.') {
153
                        // local part starts or ends with '.'
154
                        $isValid = false;
155
                    } else {
156
                        if (preg_match('/\\.\\./', $local)) {
157
                            // local part has two consecutive dots
158
                            $isValid = false;
159
                        } else {
160
                            if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
161
                                // character not valid in domain part
162
                                $isValid = false;
163
                            } else {
164
                                if (preg_match('/\\.\\./', $domain)) {
165
                                    // domain part has two consecutive dots
166
                                    $isValid = false;
167
                                } else {
168
                                    if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
169
                                        str_replace('\\\\', '', $local))
170
                                    ) {
171
                                        // character not valid in local part unless
172
                                        // local part is quoted
173
                                        if (!preg_match('/^"(\\\\"|[^"])+"$/',
174
                                            str_replace('\\\\', '', $local))
175
                                        ) {
176
                                            $isValid = false;
177
                                        }
178
                                    }
179
                                }
180
                            }
181
                        }
182
                    }
183
                }
184
            }
185
            if ($isValid && !(checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'))) {
186
                // domain not found in DNS
187
                $isValid = false;
188
            }
189
        }
190
191
        return $isValid;
192
    }
193
194
    /**
195
     * Cut string to n symbols and add delim but do not break words.
196
     *
197
     * Example:
198
     * <code>
199
     *  $string = 'this sentence is way too long';
200
     *  echo neat_trim($string, 16);
201
     * </code>
202
     *
203
     * Output: 'this sentence is...'
204
     *
205
     * @param             string    string we are operating with
206
     * @param             int   character count to cut to
207
     * @param string|null delimiter . Default: '...'
208
     *
209
     * @return string processed string
210
     *
211
     * @see    http://www.justin-cook.com/wp/2006/06/27/php-trim-a-string-without-cutting-any-words/
212
     **/
213
    public static function trim($str, $n, $delim = '...')
214
    {
215
        $len = strlen($str);
216
        if ($len > $n) {
217
            $str = str_replace("\n", '', $str);
218
            $str = str_replace("\r", '', $str);
219
            $n = $n - strlen($delim);
220
            preg_match('/(.{'.$n.'}.*?)\b/', $str, $matches);
221
222
            return rtrim($matches[1]).$delim;
223
        } else {
224
            return $str;
225
        }
226
    }
227
228
    public static function ltrim($str, $start, $delim = '...')
229
    {
230
        $pos = strpos($str, ' ', $start);
231
232
        return $delim.substr($str, $pos);
233
    }
234
235
    public static function highlight($str, $search, $trim = 100, $delim = '...')
236
    {
237
        $str = str_ireplace($search, '<span class="highlight">'.$search.'</span>', $str);
238
        if ($trim) {
239
            if (($first = strpos($str, '<span class="highlight">')) > ($trim / 2)) {
240
                $str = self::ltrim($str, $first - ($trim / 2));
241
            }
242
            $str = self::trim($str, $trim, $delim);
243
        }
244
245
        return $str;
246
    }
247
248
    /**
249
     *  UrlLinker - facilitates turning plain text URLs into HTML links.
250
     *
251
     *  Author: Søren Løvborg
252
     *
253
     *  To the extent possible under law, Søren Løvborg has waived all copyright
254
     *  and related or neighboring rights to UrlLinker.
255
     *  http://creativecommons.org/publicdomain/zero/1.0/
256
     */
257
258
    /**
259
     *  Transforms plain text into valid HTML, escaping special characters and
260
     *  turning URLs into links.
261
     */
262
    public static function link($text)
263
    {
264
        /*
265
         *  Regular expression bits used by htmlEscapeAndLinkUrls() to match URLs.
266
         */
267
        $rexScheme = 'https?://';
268
        // $rexScheme    = "$rexScheme|ftp://"; // Uncomment this line to allow FTP addresses.
269
        $rexDomain = '(?:[-a-zA-Z0-9]{1,63}\.)+[a-zA-Z][-a-zA-Z0-9]{1,62}';
270
        $rexIp = '(?:[1-9][0-9]{0,2}\.|0\.){3}(?:[1-9][0-9]{0,2}|0)';
271
        $rexPort = '(:[0-9]{1,5})?';
272
        $rexPath = '(/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?';
273
        $rexQuery = '(\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';
274
        $rexFragment = '(#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';
275
        $rexUsername = '[^]\\\\\x00-\x20\"(),:-<>[\x7f-\xff]{1,64}';
276
        $rexPassword = $rexUsername; // allow the same characters as in the username
277
        $rexUrl = "($rexScheme)?(?:($rexUsername)(:$rexPassword)?@)?($rexDomain|$rexIp)($rexPort$rexPath$rexQuery$rexFragment)";
278
        $rexTrailPunct = "[)'?.!,;:]"; // valid URL characters which are not part of the URL if they appear at the very end
279
        $rexNonUrl = "[^-_$+.!*'(),;/?:@=&a-zA-Z0-9]"; // characters that should never appear in a URL
280
        $rexUrlLinker = "{\\b$rexUrl(?=$rexTrailPunct*($rexNonUrl|$))}";
281
282
        /**
283
         *  $validTlds is an associative array mapping valid TLDs to the value true.
284
         *  Since the set of valid TLDs is not static, this array should be updated
285
         *  from time to time.
286
         *
287
         *  List source:  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
288
         *  Version 2015062200, last updated mon jun 22 07:07:02 2015 utc
289
         */
290
        $validTlds = array_fill_keys(explode(' ',
291
            '.abb .abbott .abogado .ac .academy .accenture .accountant .accountants .active .actor .ad .ads .adult .ae .aeg .aero .af .afl .ag .agency .ai .aig .airforce .al .allfinanz .alsace .am .amsterdam .an .android .ao .apartments .aq .aquarelle .ar .archi .army .arpa .as .asia .associates .at .attorney .au .auction .audio .auto .autos .aw .ax .axa .az .azure .ba .band .bank .bar .barclaycard .barclays .bargains .bauhaus .bayern .bb .bbc .bbva .bd .be .beer .berlin .best .bf .bg .bh .bharti .bi .bible .bid .bike .bing .bingo .bio .biz .bj .black .blackfriday .bloomberg .blue .bm .bmw .bn .bnpparibas .bo .boats .bond .boo .boutique .br .bridgestone .broker .brother .brussels .bs .bt .budapest .build .builders .business .buzz .bv .bw .by .bz .bzh .ca .cab .cafe .cal .camera .camp .cancerresearch .canon .capetown .capital .caravan .cards .care .career .careers .cars .cartier .casa .cash .casino .cat .catering .cbn .cc .cd .center .ceo .cern .cf .cfa .cfd .cg .ch .channel .chat .cheap .chloe .christmas .chrome .church .ci .cisco .citic .city .ck .cl .claims .cleaning .click .clinic .clothing .club .cm .cn .co .coach .codes .coffee .college .cologne .com .community .company .computer .condos .construction .consulting .contractors .cooking .cool .coop .corsica .country .coupons .courses .cr .credit .creditcard .cricket .crown .crs .cruises .cu .cuisinella .cv .cw .cx .cy .cymru .cyou .cz .dabur .dad .dance .date .dating .datsun .day .dclk .de .deals .degree .delivery .democrat .dental .dentist .desi .design .dev .diamonds .diet .digital .direct .directory .discount .dj .dk .dm .dnp .do .docs .dog .doha .domains .doosan .download .drive .durban .dvag .dz .earth .eat .ec .edu .education .ee .eg .email .emerck .energy .engineer .engineering .enterprises .epson .equipment .er .erni .es .esq .estate .et .eu .eurovision .eus .events .everbank .exchange .expert .exposed .express .fail .faith .fan .fans .farm .fashion .feedback .fi .film .finance .financial .firmdale .fish .fishing .fit .fitness .fj .fk .flights .florist .flowers .flsmidth .fly .fm .fo .foo .football .forex .forsale .foundation .fr .frl .frogans .fund .furniture .futbol .fyi .ga .gal .gallery .garden .gb .gbiz .gd .gdn .ge .gent .genting .gf .gg .ggee .gh .gi .gift .gifts .gives .gl .glass .gle .global .globo .gm .gmail .gmo .gmx .gn .gold .goldpoint .golf .goo .goog .google .gop .gov .gp .gq .gr .graphics .gratis .green .gripe .gs .gt .gu .guge .guide .guitars .guru .gw .gy .hamburg .hangout .haus .healthcare .help .here .hermes .hiphop .hitachi .hiv .hk .hm .hn .hockey .holdings .holiday .homedepot .homes .honda .horse .host .hosting .hotmail .house .how .hr .ht .hu .ibm .icbc .icu .id .ie .ifm .il .im .immo .immobilien .in .industries .infiniti .info .ing .ink .institute .insure .int .international .investments .io .iq .ir .irish .is .it .iwc .java .jcb .je .jetzt .jewelry .jlc .jll .jm .jo .jobs .joburg .jp .juegos .kaufen .kddi .ke .kg .kh .ki .kim .kitchen .kiwi .km .kn .koeln .komatsu .kp .kr .krd .kred .kw .ky .kyoto .kz .la .lacaixa .land .lasalle .lat .latrobe .lawyer .lb .lc .lds .lease .leclerc .legal .lgbt .li .liaison .lidl .life .lighting .limited .limo .link .lk .loan .loans .lol .london .lotte .lotto .love .lr .ls .lt .ltda .lu .lupin .luxe .luxury .lv .ly .ma .madrid .maif .maison .management .mango .market .marketing .markets .marriott .mba .mc .md .me .media .meet .melbourne .meme .memorial .men .menu .mg .mh .miami .microsoft .mil .mini .mk .ml .mm .mma .mn .mo .mobi .moda .moe .monash .money .montblanc .mormon .mortgage .moscow .motorcycles .mov .movie .mp .mq .mr .ms .mt .mtn .mtpc .mu .museum .mv .mw .mx .my .mz .na .nadex .nagoya .name .navy .nc .ne .nec .net .network .neustar .new .news .nexus .nf .ng .ngo .nhk .ni .nico .ninja .nissan .nl .no .np .nr .nra .nrw .ntt .nu .nyc .nz .okinawa .om .one .ong .onl .online .ooo .oracle .org .organic .osaka .otsuka .ovh .pa .page .panerai .paris .partners .parts .party .pe .pf .pg .ph .pharmacy .philips .photo .photography .photos .physio .piaget .pics .pictet .pictures .pink .pizza .pk .pl .place .play .plumbing .plus .pm .pn .pohl .poker .porn .post .pr .praxi .press .pro .prod .productions .prof .properties .property .ps .pt .pub .pw .py .qa .qpon .quebec .racing .re .realtor .recipes .red .redstone .rehab .reise .reisen .reit .ren .rent .rentals .repair .report .republican .rest .restaurant .review .reviews .rich .rio .rip .ro .rocks .rodeo .rs .rsvp .ru .ruhr .run .rw .ryukyu .sa .saarland .sale .samsung .sandvik .sandvikcoromant .sap .sarl .saxo .sb .sc .sca .scb .schmidt .scholarships .school .schule .schwarz .science .scot .sd .se .seat .sener .services .sew .sex .sexy .sg .sh .shiksha .shoes .show .shriram .si .singles .site .sj .sk .ski .sky .sl .sm .sn .sncf .so .soccer .social .software .sohu .solar .solutions .sony .soy .space .spiegel .spreadbetting .sr .st .statoil .study .style .su .sucks .supplies .supply .support .surf .surgery .suzuki .sv .swiss .sx .sy .sydney .systems .sz .taipei .tatar .tattoo .tax .taxi .tc .td .team .tech .technology .tel .temasek .tennis .tf .tg .th .thd .theater .tickets .tienda .tips .tires .tirol .tj .tk .tl .tm .tn .to .today .tokyo .tools .top .toray .toshiba .tours .town .toys .tr .trade .trading .training .travel .trust .tt .tui .tv .tw .tz .ua .ug .uk .university .uno .uol .us .uy .uz .va .vacations .vc .ve .vegas .ventures .versicherung .vet .vg .vi .viajes .video .villas .vision .vlaanderen .vn .vodka .vote .voting .voto .voyage .vu .wales .walter .wang .watch .webcam .website .wed .wedding .weir .wf .whoswho .wien .wiki .williamhill .win .windows .wme .work .works .world .ws .wtc .wtf .xbox .xerox .xin .xn--1qqw23a .xn--30rr7y .xn--3bst00m .xn--3ds443g .xn--3e0b707e .xn--45brj9c .xn--45q11c .xn--4gbrim .xn--55qw42g .xn--55qx5d .xn--6frz82g .xn--6qq986b3xl .xn--80adxhks .xn--80ao21a .xn--80asehdb .xn--80aswg .xn--90a3ac .xn--90ais .xn--9et52u .xn--b4w605ferd .xn--c1avg .xn--cg4bki .xn--clchc0ea0b2g2a9gcd .xn--czr694b .xn--czrs0t .xn--czru2d .xn--d1acj3b .xn--d1alf .xn--estv75g .xn--fiq228c5hs .xn--fiq64b .xn--fiqs8s .xn--fiqz9s .xn--fjq720a .xn--flw351e .xn--fpcrj9c3d .xn--fzc2c9e2c .xn--gecrj9c .xn--h2brj9c .xn--hxt814e .xn--i1b6b1a6a2e .xn--imr513n .xn--io0a7i .xn--j1amh .xn--j6w193g .xn--kcrx77d1x4a .xn--kprw13d .xn--kpry57d .xn--kput3i .xn--l1acc .xn--lgbbat1ad8j .xn--mgb9awbf .xn--mgba3a4f16a .xn--mgbaam7a8h .xn--mgbab2bd .xn--mgbayh7gpa .xn--mgbbh1a71e .xn--mgbc0a9azcg .xn--mgberp4a5d4ar .xn--mgbpl2fh .xn--mgbx4cd0ab .xn--mxtq1m .xn--ngbc5azd .xn--node .xn--nqv7f .xn--nqv7fs00ema .xn--nyqy26a .xn--o3cw4h .xn--ogbpf8fl .xn--p1acf .xn--p1ai .xn--pgbs0dh .xn--q9jyb4c .xn--qcka1pmc .xn--rhqv96g .xn--s9brj9c .xn--ses554g .xn--unup4y .xn--vermgensberater-ctb .xn--vermgensberatung-pwb .xn--vhquv .xn--vuq861b .xn--wgbh1c .xn--wgbl6a .xn--xhq521b .xn--xkc2al3hye2a .xn--xkc2dl3a5ee0h .xn--y9a3aq .xn--yfro4i67o .xn--ygbi2ammx .xn--zfr164b .xxx .xyz .yachts .yandex .ye .yodobashi .yoga .yokohama .youtube .yt .za .zip .zm .zone .zuerich .zw'),
292
            true);
293
294
        $html = '';
295
296
        $position = 0;
297
        while (preg_match($rexUrlLinker, $text, $match, PREG_OFFSET_CAPTURE, $position)) {
298
            list($url, $urlPosition) = $match[0];
299
300
            // Add the text leading up to the URL.
301
            $html .= substr($text, $position, $urlPosition - $position);
302
303
            $scheme = $match[1][0];
304
            $username = $match[2][0];
305
            $password = $match[3][0];
306
            $domain = $match[4][0];
307
            $afterDomain = $match[5][0]; // everything following the domain
308
            $port = $match[6][0];
309
            $path = $match[7][0];
310
311
            // Check that the TLD is valid or that $domain is an IP address.
312
            $tld = strtolower(strrchr($domain, '.'));
313
            if (preg_match('{^\.[0-9]{1,3}$}', $tld) || isset($validTlds[$tld])) {
314
                // Do not permit implicit scheme if a password is specified, as
315
                // this causes too many errors (e.g. "my email:[email protected]").
316
                if (!$scheme && $password) {
317
                    $html .= $username;
318
319
                    // Continue text parsing at the ':' following the "username".
320
                    $position = $urlPosition + strlen($username);
321
                    continue;
322
                }
323
324
                if (!$scheme && $username && !$password && !$afterDomain) {
325
                    // Looks like an email address.
326
                    $completeUrl = "mailto:$url";
327
                    $linkText = $url;
328
                } else {
329
                    // Prepend http:// if no scheme is specified
330
                    $completeUrl = $scheme ? $url : "http://$url";
331
                    $linkText = "$domain$port$path";
332
                }
333
334
                $linkHtml = '<a href="'.htmlspecialchars($completeUrl).'" target="_blank">'
335
                    .$linkText
336
                    .'</a>';
337
338
                // Cheap e-mail obfuscation to trick the dumbest mail harvesters.
339
                $linkHtml = str_replace('@', '&#64;', $linkHtml);
340
341
                // Add the hyperlink.
342
                $html .= $linkHtml;
343
            } else {
344
                // Not a valid URL.
345
                $html .= $url;
346
            }
347
348
            // Continue text parsing from after the URL.
349
            $position = $urlPosition + strlen($url);
350
        }
351
352
        // Add the remainder of the text.
353
        $html .= substr($text, $position);
354
355
        return $html;
356
    }
357
358
    public static function encrypt($text)
359
    {
360
        try {
361
            return trim(
362
                base64_encode(
363
                    gzdeflate(
364
                        mcrypt_encrypt(
365
                            MCRYPT_RIJNDAEL_256,
366
                            config('security.secret'),
367
                            $text,
368
                            MCRYPT_MODE_ECB,
369
                            mcrypt_create_iv(
370
                                mcrypt_get_iv_size(
371
                                    MCRYPT_RIJNDAEL_256,
372
                                    MCRYPT_MODE_ECB
373
                                ),
374
                                MCRYPT_RAND
375
                            )
376
                        ),
377
                        9
378
                    )
379
                )
380
            );
381
        } catch (Exception $e) {
382
            return false;
383
        }
384
    }
385
386
    public static function decrypt($text)
387
    {
388
        if (empty($text)) {
389
            return false;
390
        }
391
        $oldErrRep = error_reporting(0);
392
        try {
393
            $decrypted = trim(
394
                mcrypt_decrypt(
395
                    MCRYPT_RIJNDAEL_256,
396
                    config('security.secret'),
397
                    gzinflate(base64_decode($text)),
398
                    MCRYPT_MODE_ECB,
399
                    mcrypt_create_iv(
400
                        mcrypt_get_iv_size(
401
                            MCRYPT_RIJNDAEL_256,
402
                            MCRYPT_MODE_ECB
403
                        ),
404
                        MCRYPT_RAND
405
                    )
406
                )
407
            );
408
            error_reporting($oldErrRep);
409
410
            return $decrypted;
411
        } catch (Exception $e) {
412
            error_reporting($oldErrRep);
413
414
            return false;
415
        }
416
    }
417
418
    public static function textDiff($from, $to, $truncate = false)
419
    {
420
        require_once 'lib/finediff.php';
421
        $diff = new FineDiff($from, $to, FineDiff::$wordGranularity);
422
        if (!$truncate) {
423
            return $diff->renderDiffToHTML();
424
        } else {
425
            $html = $diff->renderDiffToHTML();
426
427
            // find first change
428
            $firstDel = strpos($html, '<del>');
429
            $firstIns = strpos($html, '<ins>');
430
            if ($firstDel === false) {
431
                $firstDel = $firstIns;
432
            }
433
            if ($firstIns === false) {
434
                $firstIns = $firstDel;
435
            }
436
            $first = min($firstDel, $firstIns);
437
            $first = max(0, $first - $truncate);
438
439
            // find last change
440
            $lastDel = strrpos($html, '</del>');
441
            $lastIns = strrpos($html, '</ins>');
442
            if ($lastDel === false) {
443
                $lastDel = $lastIns;
444
            }
445
            if ($lastIns === false) {
446
                $lastIns = $lastDel;
447
            }
448
            $last = max($lastDel, $lastIns);
449
            $last = min(strlen($html), $last + $truncate);
450
451
            // create truncated string
452
            return ($first > 0 ? '<span>....</span> ' : '').substr($html, $first,
453
                $last - $first).($last < strlen($html) ? ' <span>....</span>' : '');
454
        }
455
    }
456
457
    public static function time2str($date, $today = false)
458
    {
459
        if (!$today) {
460
            $today = new DateTime();
461
            $today = $today->format('U');
462
        }
463
        $diff = $today - $date;
464
        if ($diff == 0) {
465
            return 'now';
466
        } elseif ($diff > 0) {
467
            $day_diff = floor($diff / 86400);
468 View Code Duplication
            if ($day_diff == 0) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
469
                if ($diff < 60) {
470
                    return 'just now';
471
                }
472
                if ($diff < 120) {
473
                    return '1 minute ago';
474
                }
475
                if ($diff < 3600) {
476
                    return floor($diff / 60).' minutes ago';
477
                }
478
                if ($diff < 7200) {
479
                    return '1 hour ago';
480
                }
481
                if ($diff < 86400) {
482
                    return floor($diff / 3600).' hours ago';
483
                }
484
            }
485
            if ($day_diff == 1) {
486
                return 'yesterday';
487
            }
488
            if ($day_diff < 7) {
489
                return $day_diff.' day'.($day_diff != 1 ? 's' : '').' ago';
490
            }
491 View Code Duplication
            if ($day_diff < 31) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
492
                return ceil($day_diff / 7).' week'.(ceil($day_diff / 7) != 1 ? 's' : '').' ago';
493
            }
494
            if ($day_diff < 60) {
495
                return 'last month';
496
            }
497
498
            return date('F Y', $date);
499
        } else {
500
            $diff = abs($diff);
501
            $day_diff = floor($diff / 86400);
502 View Code Duplication
            if ($day_diff == 0) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
503
                if ($diff < 120) {
504
                    return 'in a minute';
505
                }
506
                if ($diff < 3600) {
507
                    return 'in '.floor($diff / 60).' minutes';
508
                }
509
                if ($diff < 7200) {
510
                    return 'in an hour';
511
                }
512
                if ($diff < 86400) {
513
                    return 'in '.floor($diff / 3600).' hours';
514
                }
515
            }
516
            if ($day_diff == 1) {
517
                return 'tomorrow';
518
            }
519
            if ($day_diff < 4) {
520
                return date('l', $date);
521
            }
522
            if ($day_diff < 7 + (7 - date('w'))) {
523
                return 'next week';
524
            }
525 View Code Duplication
            if (ceil($day_diff / 7) < 4) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
526
                return 'in '.ceil($day_diff / 7).' week'.(ceil($day_diff / 7) != 1 ? 's' : '');
527
            }
528
            if (date('n', $date) == date('n') + 1) {
529
                return 'next month';
530
            }
531
532
            return date('F Y', $date);
533
        }
534
    }
535
536 View Code Duplication
    public static function toBytes($str)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
537
    {
538
        $val = trim($str);
539
        $last = strtolower($str[strlen($str) - 1]);
540
        switch ($last) {
541
            case 'g':
542
                $val *= 1024;
543
            case 'm':
544
                $val *= 1024;
545
            case 'k':
546
                $val *= 1024;
547
        }
548
549
        return $val;
550
    }
551
552
    public static function toSnakeCase($camelCase)
553
    {
554
        preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $camelCase, $matches);
555
        $ret = $matches[0];
556
        foreach ($ret as &$match) {
557
            $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
558
        }
559
560
        return implode('_', $ret);
561
    }
562
}
563