1<?php
2# MantisBT - A PHP based bugtracking system
3
4# MantisBT is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 2 of the License, or
7# (at your option) any later version.
8#
9# MantisBT is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with MantisBT.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * GPC API
19 *
20 * Provides sanitisation and type conversion of user supplied data through
21 * HTTP GET, HTTP POST and cookies.
22 *
23 * @package CoreAPI
24 * @subpackage GPCAPI
25 * @copyright Copyright 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
26 * @copyright Copyright 2002  MantisBT Team - mantisbt-dev@lists.sourceforge.net
27 * @link http://www.mantisbt.org
28 *
29 * @uses config_api.php
30 * @uses constant_inc.php
31 * @uses error_api.php
32 * @uses http_api.php
33 */
34
35require_api( 'config_api.php' );
36require_api( 'constant_inc.php' );
37require_api( 'error_api.php' );
38require_api( 'http_api.php' );
39
40# Determines (once-off) whether the client is accessing this script via a
41# secure connection. If they are, we want to use the Secure cookie flag to
42# prevent the cookie from being transmitted to other domains.
43# @global boolean $g_cookie_secure_flag_enabled
44$g_cookie_secure_flag_enabled = http_is_protocol_https();
45
46/**
47 * Retrieve a GPC variable.
48 * If the variable is not set, the default is returned.
49 *
50 *  You may pass in any variable as a default (including null) but if
51 *  you pass in *no* default then an error will be triggered if the field
52 *  cannot be found
53 *
54 * @param string $p_var_name Variable name.
55 * @param mixed  $p_default  Default value.
56 * @return null
57 */
58function gpc_get( $p_var_name, $p_default = null ) {
59	if( isset( $_POST[$p_var_name] ) ) {
60		$t_result = $_POST[$p_var_name];
61	} else if( isset( $_GET[$p_var_name] ) ) {
62		$t_result = $_GET[$p_var_name];
63	} else if( func_num_args() > 1 ) {
64		# check for a default passed in (allowing null)
65		$t_result = $p_default;
66	} else {
67		error_parameters( $p_var_name );
68		trigger_error( ERROR_GPC_VAR_NOT_FOUND, ERROR );
69		$t_result = null;
70	}
71
72	return $t_result;
73}
74
75/**
76 * Check if GPC variable is set in $_POST or $_GET
77 * @param string $p_var_name Variable name to check if set by http request.
78 * @return boolean
79 */
80function gpc_isset( $p_var_name ) {
81	if( isset( $_POST[$p_var_name] ) ) {
82		return true;
83	} else if( isset( $_GET[$p_var_name] ) ) {
84		return true;
85	}
86
87	return false;
88}
89
90/**
91 * Retrieve a string GPC variable. Uses gpc_get().
92 * If you pass in *no* default, an error will be triggered if
93 * the variable does not exist
94 * @param string $p_var_name Variable name to retrieve.
95 * @param string $p_default  Default value of the string if not set(optional).
96 * @return string|null
97 */
98function gpc_get_string( $p_var_name, $p_default = null ) {
99	# Don't pass along a default unless one was given to us
100	#  otherwise we prevent an error being triggered
101	$t_args = func_get_args();
102	$t_result = call_user_func_array( 'gpc_get', $t_args );
103
104	if( is_array( $t_result ) ) {
105		error_parameters( $p_var_name );
106		trigger_error( ERROR_GPC_ARRAY_UNEXPECTED, ERROR );
107	}
108
109	if( $t_result === null ) {
110		return null;
111	} else {
112		return str_replace( "\0", '', $t_result );
113	}
114}
115
116/**
117 * Retrieve an integer GPC variable. Uses gpc_get().
118 * If you pass in *no* default, an error will be triggered if
119 * the variable does not exist
120 * @param string  $p_var_name Variable name to retrieve.
121 * @param integer $p_default  Default integer value if not set (optional).
122 * @return integer|null
123 */
124function gpc_get_int( $p_var_name, $p_default = null ) {
125	# Don't pass along a default unless one was given to us
126	#  otherwise we prevent an error being triggered
127	$t_args = func_get_args();
128	$t_result = call_user_func_array( 'gpc_get', $t_args );
129
130	if( is_array( $t_result ) ) {
131		error_parameters( $p_var_name );
132		trigger_error( ERROR_GPC_ARRAY_UNEXPECTED, ERROR );
133	}
134	$t_val = str_replace( ' ', '', trim( $t_result ) );
135	if( !preg_match( '/^-?([0-9])*$/', $t_val ) ) {
136		error_parameters( $p_var_name );
137		trigger_error( ERROR_GPC_NOT_NUMBER, ERROR );
138	}
139
140	return (int)$t_val;
141}
142
143/**
144 * Retrieve a boolean GPC variable. Uses gpc_get().
145 *  If you pass in *no* default, false will be used
146 * @param string  $p_var_name Variable name to retrieve.
147 * @param boolean $p_default  Default boolean value if not set (optional).
148 * @return boolean|null
149 */
150function gpc_get_bool( $p_var_name, $p_default = false ) {
151	$t_result = gpc_get( $p_var_name, $p_default );
152
153	if( $t_result === $p_default ) {
154		return (bool)$p_default;
155	} else {
156		if( is_array( $t_result ) ) {
157			error_parameters( $p_var_name );
158			trigger_error( ERROR_GPC_ARRAY_UNEXPECTED, ERROR );
159		}
160
161		return gpc_string_to_bool( $t_result );
162	}
163}
164
165/**
166 * see if a custom field variable is set.  Uses gpc_isset().
167 * @param string  $p_var_name          Variable name to retrieve.
168 * @param integer $p_custom_field_type Custom field type.
169 * @return boolean
170 */
171function gpc_isset_custom_field( $p_var_name, $p_custom_field_type ) {
172	$t_field_name = 'custom_field_' . $p_var_name;
173
174	switch( $p_custom_field_type ) {
175		case CUSTOM_FIELD_TYPE_DATE:
176			# date field is three dropdowns that default to 0
177			# Dropdowns are always present, so check if they are set
178			return gpc_isset( $t_field_name . '_day' ) &&
179				gpc_get_int( $t_field_name . '_day', 0 ) != 0 &&
180				gpc_isset( $t_field_name . '_month' ) &&
181				gpc_get_int( $t_field_name . '_month', 0 ) != 0 &&
182				gpc_isset( $t_field_name . '_year' ) &&
183				gpc_get_int( $t_field_name . '_year', 0 ) != 0 ;
184		case CUSTOM_FIELD_TYPE_STRING:
185		case CUSTOM_FIELD_TYPE_NUMERIC:
186		case CUSTOM_FIELD_TYPE_FLOAT:
187		case CUSTOM_FIELD_TYPE_ENUM:
188		case CUSTOM_FIELD_TYPE_EMAIL:
189		case CUSTOM_FIELD_TYPE_TEXTAREA:
190			return gpc_isset( $t_field_name ) && !is_blank( gpc_get_string( $t_field_name ) );
191		default:
192			return gpc_isset( $t_field_name );
193	}
194}
195
196/**
197 * Retrieve a custom field variable.  Uses gpc_get().
198 * If you pass in *no* default, an error will be triggered if
199 * the variable does not exist
200 * @param string  $p_var_name          Variable name.
201 * @param integer $p_custom_field_type Custom Field Type.
202 * @param mixed   $p_default           Default value.
203 * @return string
204 */
205function gpc_get_custom_field( $p_var_name, $p_custom_field_type, $p_default = null ) {
206	switch( $p_custom_field_type ) {
207		case CUSTOM_FIELD_TYPE_MULTILIST:
208		case CUSTOM_FIELD_TYPE_CHECKBOX:
209			# ensure that the default is an array, if set
210			if( ( $p_default !== null ) && !is_array( $p_default ) ) {
211				$p_default = array( $p_default );
212			}
213			$t_values = gpc_get_string_array( $p_var_name, $p_default );
214			if( is_array( $t_values ) ) {
215				return implode( '|', $t_values );
216			} else {
217				return '';
218			}
219			break;
220		case CUSTOM_FIELD_TYPE_DATE:
221			$t_day = gpc_get_int( $p_var_name . '_day', 0 );
222			$t_month = gpc_get_int( $p_var_name . '_month', 0 );
223			$t_year = gpc_get_int( $p_var_name . '_year', 0 );
224			if( ( $t_year == 0 ) || ( $t_month == 0 ) || ( $t_day == 0 ) ) {
225				if( $p_default == null ) {
226					return '';
227				} else {
228					return $p_default;
229				}
230			} else {
231				return strtotime( $t_year . '-' . $t_month . '-' . $t_day );
232			}
233			break;
234		default:
235			return gpc_get_string( $p_var_name, $p_default );
236	}
237}
238
239/**
240 * Retrieve a string array GPC variable.  Uses gpc_get().
241 * If you pass in *no* default, an error will be triggered if
242 * the variable does not exist
243 * @param string $p_var_name Variable name to retrieve.
244 * @param array  $p_default  Default value of the string array if not set.
245 * @return array
246 */
247function gpc_get_string_array( $p_var_name, array $p_default = null ) {
248	# Don't pass along a default unless one was given to us
249	# otherwise we prevent an error being triggered
250	$t_args = func_get_args();
251	$t_result = call_user_func_array( 'gpc_get', $t_args );
252
253	# If the result isn't the default we were given or an array, error
254	if( !((( 1 < func_num_args() ) && ( $t_result === $p_default ) ) || is_array( $t_result ) ) ) {
255		error_parameters( $p_var_name );
256		trigger_error( ERROR_GPC_ARRAY_EXPECTED, ERROR );
257	}
258
259	if( !is_array( $t_result ) ) {
260		return $t_result;
261	}
262	$t_array = array();
263	foreach( $t_result as $t_key => $t_value ) {
264		if( $t_value === null ) {
265			$t_array[$t_key] = null;
266		} else {
267			$t_array[$t_key] = str_replace( "\0", '', $t_value );
268		}
269	}
270	return $t_array;
271}
272
273/**
274 * Retrieve an integer array GPC variable.  Uses gpc_get().
275 * If you pass in *no* default, an error will be triggered if
276 * the variable does not exist
277 * @param string $p_var_name Variable name to retrieve.
278 * @param array  $p_default  Default value of the integer array if not set.
279 * @return array
280 */
281function gpc_get_int_array( $p_var_name, array $p_default = null ) {
282	# Don't pass along a default unless one was given to us
283	# otherwise we prevent an error being triggered
284	$t_args = func_get_args();
285	$t_result = call_user_func_array( 'gpc_get', $t_args );
286
287	# If the result isn't the default we were given or an array, error
288	if( !((( 1 < func_num_args() ) && ( $t_result === $p_default ) ) || is_array( $t_result ) ) ) {
289		error_parameters( $p_var_name );
290		trigger_error( ERROR_GPC_ARRAY_EXPECTED, ERROR );
291	}
292	if( is_array( $t_result ) ) {
293		foreach( $t_result as $t_key => $t_value ) {
294			$t_result[$t_key] = (int)$t_value;
295		}
296	}
297
298	return $t_result;
299}
300
301/**
302 * Retrieve a boolean array GPC variable.  Uses gpc_get().
303 * If you pass in *no* default, an error will be triggered if the variable does not exist.
304 * @param string $p_var_name Variable name to retrieve.
305 * @param array  $p_default  Default value of the boolean array if not set.
306 * @return array
307 */
308function gpc_get_bool_array( $p_var_name, array $p_default = null ) {
309	# Don't pass along a default unless one was given to us
310	# otherwise we prevent an error being triggered
311	$t_args = func_get_args();
312	$t_result = call_user_func_array( 'gpc_get', $t_args );
313
314	# If the result isn't the default we were given or an array, error
315	if( !((( 1 < func_num_args() ) && ( $t_result === $p_default ) ) || is_array( $t_result ) ) ) {
316		error_parameters( $p_var_name );
317		trigger_error( ERROR_GPC_ARRAY_EXPECTED, ERROR );
318	}
319
320	if( is_array( $t_result ) ) {
321		foreach( $t_result as $t_key => $t_value ) {
322			$t_result[$t_key] = gpc_string_to_bool( $t_value );
323		}
324	}
325
326	return $t_result;
327}
328
329/**
330 * Retrieve a cookie variable
331 * You may pass in any variable as a default (including null) but if
332 * you pass in *no* default then an error will be triggered if the cookie cannot be found
333 * @param string $p_var_name Variable name to retrieve.
334 * @param string $p_default  Default value if not set.
335 * @return string
336 */
337function gpc_get_cookie( $p_var_name, $p_default = null ) {
338	if( isset( $_COOKIE[$p_var_name] ) ) {
339		$t_result = $_COOKIE[$p_var_name];
340	} else if( func_num_args() > 1 ) {
341		# check for a default passed in (allowing null)
342		$t_result = $p_default;
343	} else {
344		error_parameters( $p_var_name );
345		trigger_error( ERROR_GPC_VAR_NOT_FOUND, ERROR );
346	}
347
348	return $t_result;
349}
350
351/**
352 * Set a cookie variable
353 * If $p_expire is false instead of a number, the cookie will expire when
354 * the browser is closed; if it is true, the default time from the config
355 * file will be used.
356 * If $p_path or $p_domain are omitted, defaults are used.
357 * Set $p_httponly to false if client-side Javascript needs to read/write
358 * the cookie. Otherwise it is safe to leave this value unspecified, as
359 * the default value is true.
360 * @todo this function is to be modified by Victor to add CRC... for now it just passes the parameters through to setcookie()
361 * @param string  $p_name     Cookie name to set.
362 * @param string  $p_value    Cookie value to set.
363 * @param boolean|integer $p_expire true: current browser session, false/0: cookie_time_length, otherwise: expiry time.
364 * @param string  $p_path     Cookie Path - default cookie_path configuration variable.
365 * @param string  $p_domain   Cookie Domain - default is cookie_domain configuration variable.
366 * @param boolean $p_httponly Default true.
367 * @return boolean - true on success, false on failure
368 */
369function gpc_set_cookie( $p_name, $p_value, $p_expire = false, $p_path = null, $p_domain = null, $p_httponly = true ) {
370	global $g_cookie_secure_flag_enabled;
371
372	if( false === $p_expire ) {
373		$p_expire = 0;
374	} else if( true === $p_expire ) {
375		$t_cookie_length = config_get_global( 'cookie_time_length' );
376		$p_expire = time() + $t_cookie_length;
377	}
378
379	if( null === $p_path ) {
380		$p_path = config_get_global( 'cookie_path' );
381	}
382
383	if( null === $p_domain ) {
384		$p_domain = config_get_global( 'cookie_domain' );
385	}
386
387	return setcookie( $p_name, $p_value, $p_expire, $p_path, $p_domain, $g_cookie_secure_flag_enabled, true );
388}
389
390/**
391 * Clear a cookie variable
392 * @param string $p_name   Cookie clear to set.
393 * @param string $p_path   Cookie path.
394 * @param string $p_domain Cookie domain.
395 * @return boolean
396 */
397function gpc_clear_cookie( $p_name, $p_path = null, $p_domain = null ) {
398	if( null === $p_path ) {
399		$p_path = config_get_global( 'cookie_path' );
400	}
401	if( null === $p_domain ) {
402		$p_domain = config_get_global( 'cookie_domain' );
403	}
404
405	if( isset( $_COOKIE[$p_name] ) ) {
406		unset( $_COOKIE[$p_name] );
407	}
408
409	# don't try to send cookie if headers are send (guideweb)
410	if( !headers_sent() ) {
411		return setcookie( $p_name, '', -1, $p_path, $p_domain );
412	} else {
413		return false;
414	}
415}
416
417/**
418 * Retrieve a file variable
419 * You may pass in any variable as a default (including null) but if
420 * you pass in *no* default then an error will be triggered if the file
421 * cannot be found
422 * @param string $p_var_name Variable name.
423 * @param mixed  $p_default  Default value.
424 * @return mixed
425 */
426function gpc_get_file( $p_var_name, $p_default = null ) {
427	if( isset( $_FILES[$p_var_name] ) ) {
428		# FILES are not escaped even if magic_quotes is ON, this applies to Windows paths.
429		$t_result = $_FILES[$p_var_name];
430	} else if( func_num_args() > 1 ) {
431		# check for a default passed in (allowing null)
432		$t_result = $p_default;
433	} else {
434		error_parameters( $p_var_name );
435		trigger_error( ERROR_GPC_VAR_NOT_FOUND, ERROR );
436	}
437
438	return $t_result;
439}
440
441/**
442 * Convert a POST/GET parameter to an array if it is not already one.
443 * There is no return value from this function - The $_POST/$_GET are updated as appropriate.
444 * @param string $p_var_name The name of the parameter.
445 * @return void
446 */
447function gpc_make_array( $p_var_name ) {
448	if( isset( $_POST[$p_var_name] ) && !is_array( $_POST[$p_var_name] ) ) {
449		$_POST[$p_var_name] = array(
450			$_POST[$p_var_name],
451		);
452	}
453
454	if( isset( $_GET[$p_var_name] ) && !is_array( $_GET[$p_var_name] ) ) {
455		$_GET[$p_var_name] = array(
456			$_GET[$p_var_name],
457		);
458	}
459}
460
461/**
462 * Convert a string to a bool
463 * @param string $p_string A string to convert to a boolean value.
464 * @return boolean
465 */
466function gpc_string_to_bool( $p_string ) {
467	$t_value = trim( strtolower( $p_string ) );
468	switch ( $t_value ) {
469		case 'off':
470		case 'no':
471		case 'n':
472		case 'false':
473		case '0':
474		case '':
475			return false;
476		default:
477			return true;
478	}
479}
480