]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions-formatting.php
Allow filtering in URL sanitization. Fixes issue 1194.
[Github/YOURLS.git] / includes / functions-formatting.php
1 <?php\r
2 /*\r
3  * YOURLS\r
4  * Function library for anything related to formatting / validating / sanitizing\r
5  */\r
6 \r
7 // function to convert an integer (1337) to a string (3jk).\r
8 function yourls_int2string( $num, $chars = null ) {\r
9         if( $chars == null )\r
10                 $chars = yourls_get_shorturl_charset();\r
11         $string = '';\r
12         $len = strlen( $chars );\r
13         while( $num >= $len ) {\r
14                 $mod = bcmod( $num, $len );\r
15                 $num = bcdiv( $num, $len );\r
16                 $string = $chars[ $mod ] . $string;\r
17         }\r
18         $string = $chars[ $num ] . $string;\r
19         \r
20         return yourls_apply_filter( 'int2string', $string, $num, $chars );\r
21 }\r
22 \r
23 // function to convert a string (3jk) to an integer (1337)\r
24 function yourls_string2int( $string, $chars = null ) {\r
25         if( $chars == null )\r
26                 $chars = yourls_get_shorturl_charset();\r
27         $integer = 0;\r
28         $string = strrev( $string  );\r
29         $baselen = strlen( $chars );\r
30         $inputlen = strlen( $string );\r
31         for ($i = 0; $i < $inputlen; $i++) {\r
32                 $index = strpos( $chars, $string[$i] );\r
33                 $integer = bcadd( $integer, bcmul( $index, bcpow( $baselen, $i ) ) );\r
34         }\r
35 \r
36         return yourls_apply_filter( 'string2int', $integer, $string, $chars );\r
37 }\r
38 \r
39 // return a unique(ish) hash for a string to be used as a valid HTML id\r
40 function yourls_string2htmlid( $string ) {\r
41         return yourls_apply_filter( 'string2htmlid', 'y'.abs( crc32( $string ) ) );\r
42 }\r
43 \r
44 // Make sure a link keyword (ie "1fv" as in "site.com/1fv") is valid.\r
45 function yourls_sanitize_string( $string ) {\r
46         // make a regexp pattern with the shorturl charset, and remove everything but this\r
47         $pattern = yourls_make_regexp_pattern( yourls_get_shorturl_charset() );\r
48         $valid = substr( preg_replace( '![^'.$pattern.']!', '', $string ), 0, 199 );\r
49         \r
50         return yourls_apply_filter( 'sanitize_string', $valid, $string );\r
51 }\r
52 \r
53 // Alias function. I was always getting it wrong.\r
54 function yourls_sanitize_keyword( $keyword ) {\r
55         return yourls_sanitize_string( $keyword );\r
56 }\r
57 \r
58 // Sanitize a page title. No HTML per W3C http://www.w3.org/TR/html401/struct/global.html#h-7.4.2\r
59 function yourls_sanitize_title( $title ) {\r
60         // TODO: make stronger Implement KSES?\r
61         $title = strip_tags( $title );\r
62         // Remove extra white space\r
63         $title = preg_replace( "/\s+/", ' ', trim( $title ) );\r
64         return $title;\r
65 }\r
66 \r
67 // A few sanity checks on the URL\r
68 function yourls_sanitize_url( $unsafe_url, $force_protocol = true, $force_lowercase = true ) {\r
69         // make sure there's only one 'http://' at the beginning (prevents pasting a URL right after the default 'http://')\r
70         $url = str_replace( \r
71                 array( 'http://http://', 'http://https://' ),\r
72                 array( 'http://',        'https://'        ),\r
73                 $unsafe_url\r
74         );\r
75 \r
76         if( $force_protocol ) {\r
77                 // make sure there's a protocol, add http:// if not\r
78                 if ( !preg_match('!^([a-zA-Z]+://)!', $url ) )\r
79                         $url = 'http://'.$url;\r
80         }\r
81         \r
82         if( $force_lowercase ) {\r
83                 // force scheme and domain to lowercase - see issue 591\r
84                 preg_match( '!^([a-zA-Z]+://([^/]+))(.*)$!', $url, $matches );\r
85                 if( isset( $matches[1] ) && isset( $matches[3] ) )\r
86                         $url = strtolower( $matches[1] ) . $matches[3];\r
87         }\r
88         \r
89         // clean and shave\r
90         $url = yourls_clean_url( $url );\r
91         $url = substr( $url, 0, 1999 );\r
92         \r
93         return yourls_apply_filter( 'sanitize_url', $url, $unsafe_url, $force_protocol, $force_lowercase );\r
94 }\r
95 \r
96 // Function to filter all invalid characters from a URL. Stolen from WP's clean_url()\r
97 function yourls_clean_url( $url ) {\r
98         $url = preg_replace( '|[^a-z0-9-~+_.?\[\]\^#=!&;,/:%@$\|*`\'<>"()\\x80-\\xff\{\}]|i', '', $url );\r
99         $strip = array( '%0d', '%0a', '%0D', '%0A' );\r
100         $url = yourls_deep_replace( $strip, $url );\r
101         $url = str_replace( ';//', '://', $url );\r
102         $url = str_replace( '&amp;', '&', $url ); // Revert & not to break query strings\r
103         \r
104         return $url;\r
105 }\r
106 \r
107 // Perform a replacement while a string is found, eg $subject = '%0%0%0DDD', $search ='%0D' -> $result =''\r
108 // Stolen from WP's _deep_replace\r
109 function yourls_deep_replace( $search, $subject ){\r
110         $found = true;\r
111         while($found) {\r
112                 $found = false;\r
113                 foreach( (array) $search as $val ) {\r
114                         while( strpos( $subject, $val ) !== false ) {\r
115                                 $found = true;\r
116                                 $subject = str_replace( $val, '', $subject );\r
117                         }\r
118                 }\r
119         }\r
120         \r
121         return $subject;\r
122 }\r
123 \r
124 // Make sure an integer is a valid integer (PHP's intval() limits to too small numbers)\r
125 // TODO FIXME FFS: unused ?\r
126 function yourls_sanitize_int( $in ) {\r
127         return ( substr( preg_replace( '/[^0-9]/', '', strval( $in ) ), 0, 20 ) );\r
128 }\r
129 \r
130 // Make sure a integer is safe\r
131 // Note: this is not checking for integers, since integers on 32bits system are way too limited\r
132 // TODO: find a way to validate as integer\r
133 function yourls_intval( $in ) {\r
134         return yourls_escape( $in );\r
135 }\r
136 \r
137 // Escape a string\r
138 function yourls_escape( $in ) {\r
139         return mysql_real_escape_string( $in );\r
140 }\r
141 \r
142 // Sanitize an IP address\r
143 function yourls_sanitize_ip( $ip ) {\r
144         return preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip );\r
145 }\r
146 \r
147 // Make sure a date is m(m)/d(d)/yyyy, return false otherwise\r
148 function yourls_sanitize_date( $date ) {\r
149         if( !preg_match( '!^\d{1,2}/\d{1,2}/\d{4}$!' , $date ) ) {\r
150                 return false;\r
151         }\r
152         return $date;\r
153 }\r
154 \r
155 // Sanitize a date for SQL search. Return false if malformed input.\r
156 function yourls_sanitize_date_for_sql( $date ) {\r
157         if( !yourls_sanitize_date( $date ) )\r
158                 return false;\r
159         return date( 'Y-m-d', strtotime( $date ) );\r
160 }\r
161 \r
162 // Return word or words if more than one\r
163 function yourls_plural( $word, $count=1 ) {\r
164         return $word . ($count > 1 ? 's' : '');\r
165 }\r
166 \r
167 // Return trimmed string\r
168 function yourls_trim_long_string( $string, $length = 60, $append = '[...]' ) {\r
169         $newstring = $string;\r
170         if( function_exists( 'mb_substr' ) ) {\r
171                 if ( mb_strlen( $newstring ) > $length ) {\r
172                         $newstring = mb_substr( $newstring, 0, $length - mb_strlen( $append ), 'UTF-8' ) . $append;     \r
173                 }\r
174         } else {\r
175                 if ( strlen( $newstring ) > $length ) {\r
176                         $newstring = substr( $newstring, 0, $length - strlen( $append ) ) . $append;    \r
177                 }\r
178         }\r
179         return yourls_apply_filter( 'trim_long_string', $newstring, $string, $length, $append );\r
180 }\r
181 \r
182 // Sanitize a version number (1.4.1-whatever -> 1.4.1)\r
183 function yourls_sanitize_version( $ver ) {\r
184         return preg_replace( '/[^0-9.]/', '', $ver );\r
185 }\r
186 \r
187 // Sanitize a filename (no Win32 stuff)\r
188 function yourls_sanitize_filename( $file ) {\r
189         $file = str_replace( '\\', '/', $file ); // sanitize for Win32 installs\r
190         $file = preg_replace( '|/+|' ,'/', $file ); // remove any duplicate slash\r
191         return $file;\r
192 }\r
193 \r
194 // Check if a string seems to be UTF-8. Stolen from WP.\r
195 function yourls_seems_utf8( $str ) {\r
196         $length = strlen( $str );\r
197         for ( $i=0; $i < $length; $i++ ) {\r
198                 $c = ord( $str[ $i ] );\r
199                 if ( $c < 0x80 ) $n = 0; # 0bbbbbbb\r
200                 elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb\r
201                 elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb\r
202                 elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb\r
203                 elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb\r
204                 elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b\r
205                 else return false; # Does not match any model\r
206                 for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?\r
207                         if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))\r
208                                 return false;\r
209                 }\r
210         }\r
211         return true;\r
212 }\r
213 \r