/** * Save the item. * * @param array $src The source. * * @return $this * * @since 1.0 * @throws \UnexpectedValueException */ public function save(array $src) { $filter = new InputFilter(); $data = array(); $data['id'] = $filter->clean($src['id'], 'int'); if (!$data['id']) { throw new \UnexpectedValueException('Missing ID'); } $data['params'] = json_encode($src['params']); (new TableUsers($this->db))->save($data); return $this; }
/** * Gets an array of values from the request. * * @param array $vars Associative array of keys and filter types to apply. * If empty and datasource is null, all the input data will be returned * but filtered using the default case in JFilterInput::clean. * @param mixed $datasource Array to retrieve data from, or null * * @return mixed The filtered input data. * * @since 1.0 */ public function getArray(array $vars = array(), $datasource = null) { if (empty($vars) && is_null($datasource)) { $vars = $this->data; } $results = array(); foreach ($vars as $k => $v) { if (is_array($v)) { if (is_null($datasource)) { $results[$k] = $this->getArray($v, $this->get($k, null, 'array')); } else { $results[$k] = $this->getArray($v, $datasource[$k]); } } else { if (is_null($datasource)) { $results[$k] = $this->get($k, null, $v); } elseif (isset($datasource[$k])) { $results[$k] = $this->filter->clean($datasource[$k], $v); } else { $results[$k] = $this->filter->clean(null, $v); } } } return $results; }
/** * Returns a session storage handler object, only creating it if it doesn't already exist. * * @param string $name The session store to instantiate * @param array $options Array of options * * @return Storage * * @since 1.0 */ public static function getInstance($name = 'none', $options = array()) { $filter = new InputFilter(); $name = strtolower($filter->clean($name, 'word')); if (empty(self::$instances[$name])) { $class = '\\Joomla\\Session\\Storage\\' . ucfirst($name); if (!class_exists($class)) { $path = __DIR__ . '/storage/' . $name . '.php'; if (file_exists($path)) { require_once $path; } else { // No attempt to die gracefully here, as it tries to close the non-existing session exit('Unable to load session storage class: ' . $name); } } self::$instances[$name] = new $class($options); } return self::$instances[$name]; }
/** * Method to bind an associative array or object to the AbstractDatabaseTable instance. This * method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @param mixed $source An associative array or object to bind to the AbstractDatabaseTable instance. * @param mixed $ignore An optional array or space separated list of properties to ignore while binding. * * @return $this Method allows chaining * * @since 1.0 * @throws \UnexpectedValueException */ public function bind($source, $ignore = array()) { if (false == is_array($source)) { throw new \UnexpectedValueException(__METHOD__ . ' only accepts arrays :('); } $src = new Registry($source); $filter = new InputFilter(); $this->title = $filter->clean($src->get('title')); $this->group_id = (int) $src->get('group_id'); $this->project_id = (int) $src->get('project_id'); $this->system = (int) $src->get('system'); // The following values come in as checkboxes ¡: "ON" or not set. $this->can_view = $src->get('can_view') ? 1 : 0; $this->can_create = $src->get('can_create') ? 1 : 0; $this->can_edit = $src->get('can_edit') ? 1 : 0; $this->can_editown = $src->get('can_editown') ? 1 : 0; $this->can_manage = $src->get('can_manage') ? 1 : 0; return $this; }
/** * Execute a test case with clean() using custom class blacklist filter settings (strips bad tags). * * @param string $type The type of input * @param string $data The input * @param string $expect The expected result for this test. * @param string $message The failure message identifying the source of the test case. * * @return void * * @dataProvider blacklistClass */ public function testCleanWithClassBlackList($type, $data, $expect, $message) { $filter = new InputFilter(null, array('class'), 1, 1); $this->assertThat($filter->clean($data, $type), $this->equalTo($expect), $message); }
/** * Save the item. * * @param array $src The source. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function save(array $src) { $filter = new InputFilter(); $data = array(); $data['id'] = $filter->clean($src['id'], 'int'); $data['status'] = $filter->clean($src['status'], 'int'); $data['priority'] = $filter->clean($src['priority'], 'int'); $data['title'] = $filter->clean($src['title'], 'string'); $data['build'] = $filter->clean($src['build'], 'string'); $data['description'] = $filter->clean($src['description'], 'raw'); $data['description_raw'] = $filter->clean($src['description_raw'], 'raw'); $data['rel_number'] = $filter->clean($src['rel_number'], 'int'); $data['rel_type'] = $filter->clean($src['rel_type'], 'int'); $data['commits'] = isset($src['commits']) ? $src['commits'] : ''; $data['pr_head_sha'] = isset($src['pr_head_sha']) ? $src['pr_head_sha'] : ''; if (isset($src['easy'])) { $data['easy'] = $filter->clean($src['easy'], 'int'); } if (isset($src['modified_date'])) { $data['modified_date'] = $filter->clean($src['modified_date'], 'string'); } $data['modified_by'] = $filter->clean($src['modified_by'], 'string'); $data['milestone_id'] = isset($src['milestone_id']) ? $filter->clean($src['milestone_id'], 'int') : null; $state = $src['new_state']; $changedState = $src['old_state'] != $src['new_state']; // If the item has moved from open to closed, add the close data if ($state == 'closed' && $changedState) { $data['closed_date'] = (new Date())->format($this->getDb()->getDateFormat()); $data['closed_by'] = $data['modified_by']; } // If the item has moved from closed to open, remove the close data if ($state == 'open' && $changedState) { $data['closed_date'] = null; $data['closed_by'] = null; } $data['labels'] = null; if (!empty($src['labels'])) { $labels = []; foreach ($src['labels'] as $labelId) { $labels[] = (int) $labelId; } $data['labels'] = implode(',', $labels); } if (!$data['id']) { throw new \RuntimeException('Missing ID'); } $table = new IssuesTable($this->db); $table->load($data['id'])->bind($data)->check()->store(true); return $this; }
/** * Method to be called by another php script. Processes for XSS and * specified bad code. * * @param mixed $source Input string/array-of-string to be 'cleaned' * @param string $type The return type for the variable: * INT: An integer, or an array of integers, * UINT: An unsigned integer, or an array of unsigned integers, * FLOAT: A floating point number, or an array of floating point numbers, * BOOLEAN: A boolean value, * WORD: A string containing A-Z or underscores only (not case sensitive), * ALNUM: A string containing A-Z or 0-9 only (not case sensitive), * CMD: A string containing A-Z, 0-9, underscores, periods or hyphens (not case sensitive), * BASE64: A string containing A-Z, 0-9, forward slashes, plus or equals (not case sensitive), * STRING: A fully decoded and sanitised string (default), * HTML: A sanitised string, * ARRAY: An array, * PATH: A sanitised file path, or an array of sanitised file paths, * TRIM: A string trimmed from normal, non-breaking and multibyte spaces * USERNAME: Do not use (use an application specific filter), * RAW: The raw string is returned with no filtering, * unknown: An unknown filter will act like STRING. If the input is an array it will return an * array of fully decoded and sanitised strings. * * @return mixed 'Cleaned' version of input parameter * * @since 11.1 */ public function clean($source, $type = 'string') { // Strip Unicode Supplementary Characters when requested to do so if ($this->stripUSC) { // Alternatively: preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xE2\xAF\x91", $source) but it'd be slower. $source = $this->stripUSC($source); } return parent::clean($source, $type); }
/** * Clean the field values. * * @param array $fields The field array. * * @return array Container with cleaned fields * * @since 1.0 */ private function _cleanFields(array $fields) { $filter = new InputFilter(); // Selects are integers. foreach (array_keys($fields['selects']) as $key) { if (!$fields['selects'][$key]) { unset($fields['selects'][$key]); } else { $fields['selects'][$key] = (int) $fields['selects'][$key]; } } // Textfields are strings. foreach (array_keys($fields['textfields']) as $key) { if (!$fields['textfields'][$key]) { unset($fields['textfields'][$key]); } else { $fields['textfields'][$key] = $filter->clean($fields['textfields'][$key]); } } // Checkboxes are selected if they are present. foreach (array_keys($fields['checkboxes']) as $key) { if (!$fields['checkboxes'][$key]) { unset($fields['checkboxes'][$key]); } else { $fields['checkboxes'][$key] = 1; } } return $fields; }
/** * Get an item by alias * * @param string $alias The alias of the category * * @return object * * @since 1.0 */ public function getByAlias($alias = '') { $db = $this->getDb(); $query = $db->getQuery(true); $projectId = $this->getProject()->project_id; $query->select('*')->from('#__issues_categories')->where($db->quoteName('project_id') . '=' . $projectId); $filter = new InputFilter(); $alias = $filter->clean($alias, 'cmd'); if ($alias) { $alias = $db->quote('%' . $db->escape(StringHelper::strtolower($alias), true) . '%', false); $query->where($db->quoteName('alias') . ' LIKE ' . $alias); } $item = $db->setQuery($query)->loadObject(); return $item; }
/** * Handle callback from PayPal. * * @return boolean True if valid. * * @since 1.0.0 */ private function IPNCallback() { $app = JFactory::getDbo(); JLoader::import('joomla.utilities.date'); $data = $_POST; if (empty($data)) { $app->close(); } $isValid = $this->isValidIPN($data); $filter = new InputFilter(); foreach ($data as $k => $v) { $data[$k] = $filter->clean($v); } if (!$isValid) { $data['cmdonation_failure_reason'] = 'PayPal reports transaction as invalid'; } if ($isValid) { $validTypes = array('express_checkout', 'recurring_payment', 'recurring_payment_profile_created'); $isValid = in_array($data['txn_type'], $validTypes); if (!$isValid) { $data['cmdonation_failure_reason'] = "Transaction type " . $data['txn_type'] . " can't be processed by this payment plugin."; } else { $recurring = $data['txn_type'] == 'recurring_payment'; } } if ($isValid) { $id = $recurring ? $data['rp_invoice_id'] : $data['invoice']; $donation = null; if ($id > 0) { $db = JFactory::getDbo(); $query = $db->getQuery(true)->select('*')->from($db->quoteName('#__cmdonation_donations'))->where($db->quoteName('id') . ' = ' . $db->quote($id)); $donation = $db->setQuery($query)->loadObject(); if (!isset($donation->id) || $donation->id != $id) { $donation = null; $isValid = false; } } else { $isValid = false; } if (!$isValid) { $data['cmdonation_failure_reason'] = 'The donation ID is invalid'; } } // Check that amount is correct. if ($isValid) { $eAmount = floatval($data['mc_gross']); $gAmount = $donation->amount; $isValid = $gAmount - $eAmount < 0.01; if (!$isValid) { $data['cmdonation_failure_reason'] = "Amounts do not match. Expect {$eAmount}, but get {$gAmount}."; } } // Check that currency is correct. if ($isValid) { $eCurrency = strtoupper($this->getCurrency()); $gCurrency = strtoupper($data['mc_currency']); if ($eCurrency != $gCurrency) { $isValid = false; $data['cmdonation_failure_reason'] = "Currency code doesn't match. Expect {$eCurrency}, but get {$gCurrency}."; } } // Log the IPN data. $this->logIPN($data, $isValid); // Fraud attempt? Do nothing more! if (!$isValid) { $app->close(); } // Check payment status switch ($data['payment_status']) { case 'Canceled_Reversal': case 'Completed': $status = 'COMPLETED'; break; case 'Refunded': $status = 'REFUNDED'; break; default: $status = "INCOMPLETED"; break; } $db = JFactory::getDbo(); $now = new JDate(); if ($recurring) { // Save new donation. $donationData = array('campaign_id' => $donation->campaign_id, 'first_name' => $donation->first_name, 'last_name' => $donation->last_name, 'email' => $donation->email, 'country_code' => $donation->country_code, 'anonymous' => $donation->anonymous, 'recurring' => $recurring, 'recurring_cycle' => $donation->recurring_cycle, 'first_donation_id' => $donation->id, 'amount' => $data['mc_gross'], 'payment_method_id' => $donation->payment_method_id, 'status' => $status, 'transaction_id' => $data['txn_id'], 'transaction_token' => '', 'transaction_params' => json_encode($data), 'created' => $now->toSql()); if ($status == 'COMPLETED') { $donationData['completed'] = $now->toSql(); } $db->insertObject('#__cmdonation_donations', $donationData, 'id'); } else { // Update old donation. $query = $db->getQuery(true)->update($db->quoteName('#__cmdonation_donations'))->set(array($db->quoteName('status') . ' = ' . $db->quote($status), $db->quoteName('transaction_params') . ' = ' . $db->quote(json_encode($data))))->where($db->quoteName('id') . ' = ' . $db->quote($donation->id)); if ($status == 'COMPLETED') { $query->set($db->quoteName('completed') . ' = ' . $db->quote($now->toSql())); } $db->setQuery($query); $db->execute(); } $app->close(); }
/** * Method to apply an input filter to a value based on field data. * * @param string $element The XML element object representation of the form field. * @param mixed $value The value to filter for the field. * * @return mixed The filtered value. * * @since 1.0 */ protected function filterField($element, $value) { // Make sure there is a valid SimpleXMLElement. if (!$element instanceof \SimpleXMLElement) { return false; } // Get the field filter type. $filter = (string) $element['filter']; // Process the input value based on the filter. $return = null; switch (strtoupper($filter)) { // Do nothing, thus leaving the return value as null. case 'UNSET': break; // No Filter. // No Filter. case 'RAW': $return = $value; break; // Filter the input as an array of integers. // Filter the input as an array of integers. case 'INT_ARRAY': // Make sure the input is an array. if (is_object($value)) { $value = get_object_vars($value); } $value = is_array($value) ? $value : array($value); $value = ArrayHelper::toInteger($value); $return = $value; break; // Filter safe HTML. // Filter safe HTML. case 'SAFEHTML': $filterInput = new Filter\InputFilter(null, null, 1, 1); $return = $filterInput->clean($value, 'string'); break; // Ensures a protocol is present in the saved field. Only use when // the only permitted protocols requre '://'. See Rule\Url for list of these. // Ensures a protocol is present in the saved field. Only use when // the only permitted protocols requre '://'. See Rule\Url for list of these. case 'URL': if (empty($value)) { return false; } $filterInput = new Filter\InputFilter(); $value = $filterInput->clean($value, 'html'); $value = trim($value); // Check for a protocol $protocol = parse_url($value, PHP_URL_SCHEME); // If there is no protocol and the relative option is not specified, // we assume that it is an external URL and prepend http://. if ($element['type'] == 'url' && !$protocol && !$element['relative'] || !$element['type'] == 'url' && !$protocol) { $protocol = 'http'; // If it looks like an internal link, then add the root. if (substr($value, 0) == 'index.php') { $value = Uri::root() . $value; } // Otherwise we treat it is an external link. // Put the url back together. $value = $protocol . '://' . $value; } elseif (!$protocol && $element['relative']) { $host = Uri::getInstance('SERVER')->gethost(); // If it starts with the host string, just prepend the protocol. if (substr($value, 0) == $host) { $value = 'http://' . $value; } else { $value = Uri::root() . $value; } } $return = $value; break; case 'TEL': $value = trim($value); // Does it match the NANP pattern? if (preg_match('/^(?:\\+?1[-. ]?)?\\(?([2-9][0-8][0-9])\\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/', $value) == 1) { $number = (string) preg_replace('/[^\\d]/', '', $value); if (substr($number, 0, 1) == 1) { $number = substr($number, 1); } if (substr($number, 0, 2) == '+1') { $number = substr($number, 2); } $result = '1.' . $number; } elseif (preg_match('/^\\+(?:[0-9] ?){6,14}[0-9]$/', $value) == 1) { $countrycode = substr($value, 0, strpos($value, ' ')); $countrycode = (string) preg_replace('/[^\\d]/', '', $countrycode); $number = strstr($value, ' '); $number = (string) preg_replace('/[^\\d]/', '', $number); $result = $countrycode . '.' . $number; } elseif (preg_match('/^\\+[0-9]{1,3}\\.[0-9]{4,14}(?:x.+)?$/', $value) == 1) { if (strstr($value, 'x')) { $xpos = strpos($value, 'x'); $value = substr($value, 0, $xpos); } $result = str_replace('+', '', $value); } elseif (preg_match('/[0-9]{1,3}\\.[0-9]{4,14}$/', $value) == 1) { $result = $value; } else { $value = (string) preg_replace('/[^\\d]/', '', $value); if ($value != null && strlen($value) <= 15) { $length = strlen($value); // If it is fewer than 13 digits assume it is a local number if ($length <= 12) { $result = '.' . $value; } else { // If it has 13 or more digits let's make a country code. $cclen = $length - 12; $result = substr($value, 0, $cclen) . '.' . substr($value, $cclen); } } else { $result = ''; } } $return = $result; break; default: // Check for a callback filter. if (strpos($filter, '::') !== false && is_callable(explode('::', $filter))) { $return = call_user_func(explode('::', $filter), $value); } elseif (function_exists($filter)) { $return = call_user_func($filter, $value); } else { $filterInput = new Filter\InputFilter(); $return = $filterInput->clean($value, $filter); } break; } return $return; }
/** * Save the item. * * @param array $src The source. * * @return $this * * @since 1.0 * @throws \RuntimeException */ public function save(array $src) { $filter = new InputFilter(); $data = array(); $data['id'] = $filter->clean($src['id'], 'int'); $data['status'] = $filter->clean($src['status'], 'int'); $data['priority'] = $filter->clean($src['priority'], 'int'); $data['title'] = $filter->clean($src['title'], 'string'); $data['build'] = $filter->clean($src['build'], 'string'); $data['description'] = $filter->clean($src['description'], 'raw'); $data['description_raw'] = $filter->clean($src['description_raw'], 'raw'); $data['rel_number'] = $filter->clean($src['rel_number'], 'int'); $data['rel_type'] = $filter->clean($src['rel_type'], 'int'); $data['easy'] = $filter->clean($src['easy'], 'int'); $data['modified_by'] = $filter->clean($src['modified_by'], 'string'); if (!$data['id']) { throw new \RuntimeException('Missing ID'); } $table = new IssuesTable($this->db); $table->load($data['id'])->bind($data)->check()->store(true); return $this; }