/** * Prepares a SQL query for safe execution. Uses sprintf()-like syntax. * * @version 1.0 * @since 1.0 * * @param array $args | Query args array * => VAL @param string [0] | First key in array is query string in vsprintf() format * => VAL @param mixed [N] | Each successive key is a var referred to in the query string * * @return string | Prepared query string */ function prepare($query, $params = null) { // Force floats to be locale unaware $query = preg_replace('|(?<!%)%f|', '%F', $query); // Quote the strings, avoiding escaped strings like %%s $query = preg_replace('|(?<!%)%s|', "'%s'", $query); // Replace our %r raw string token with an unquoted %s $query = preg_replace('|(?<!%)%r|', "%s", $query); $escaped_params = array(); if ($params) { $cast = new FOX_cast(); foreach ($params as $param) { if (!FOX_sUtil::keyExists('escape', $param) || !FOX_sUtil::keyExists('val', $param) || !FOX_sUtil::keyExists('php', $param) || !FOX_sUtil::keyExists('sql', $param)) { $text = "SAFETY INTERLOCK TRIP [ANTI SQL-INJECTION] - All data objects passed to the "; $text .= "database driver must include 'val', 'escape', 'php', and 'sql' parameters. This "; $text .= "interlock cannot be disabled."; throw new FOX_exception(array('numeric' => 1, 'text' => $text, 'data' => $param, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } try { $cast_val = $cast->PHPToSQL($param['val'], $param['php'], $param['sql']); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error while casting parameter", 'data' => array("val" => $param['val'], "php" => $param['php'], "sql" => $param['sql']), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($param['escape'] !== false) { // NOTE: parameters are in reverse order from mysqli_real_escape_string() $escaped_params[] = mysql_real_escape_string($cast_val, $this->dbh); } else { $escaped_params[] = $cast_val; } } unset($param); } $result = vsprintf($query, $escaped_params); return $result; }
/** * Builds an indate [INsert-upDATE] query for processing by $wpdb->prepare(). * * @version 1.0 * @since 1.0 * * @param array $struct | Structure of the db table, @see class FOX_db header for examples * * @param array/object $data | Class with $column_1, $column_2 in the namespace, or array of the form ("column_1"=>"value_1", "column_2"=>"value_2") * => KEY @param string | Name of the db column this key describes * => VAL @param int/string | Value to assign to the column * * @param bool/array $columns | Columns to use in query. NULL to select all columns. * => VAL @param string $mode | Column operating mode. "include" | "exclude" * => VAL @param string/array $col | Single column name as string. Multiple column names as array of strings * * @return array | Exception on failure. Query array on success. */ public function buildIndateQuery($struct, $data, $columns = null) { // Switch between unit test mode (pass as array) and // normal mode (pass as class name) // ==================================================== if (is_string($struct)) { $struct = call_user_func(array($struct, '_struct')); } // ==================================================== $params_list = array(); $columns_list = array(); $columns_list = array_keys($struct["columns"]); // Handle data passed as array where the array has missing // or nonexistent db column names // ===================================================== if (is_array($data)) { $columns_list = array_intersect($columns_list, array_keys($data)); } // Include or exclude one or more columns from the query // ###################################################### if ($columns != null) { if (!is_array($columns["col"])) { // Handle single column name as string $temp = array(); $temp[0] = $columns["col"]; $columns["col"] = $temp; } if ($columns["mode"] == "include") { $column_names = array_intersect($columns_list, $columns["col"]); } elseif ($columns["mode"] == "exclude") { $column_names = array_diff($columns_list, $columns["col"]); } } else { $column_names = $columns_list; } // Build the INSERT columns string // ###################################################### $columns_count = count($column_names) - 1; $columns_left = $columns_count; foreach ($column_names as $column_name) { $insert_columns_string .= $column_name; if ($columns_left != 0) { $insert_columns_string .= ", "; $columns_left--; } } // CASE 1 - Array Mode // ============================== if (is_array($data)) { $cast = new FOX_cast(); $query_formats .= "("; $columns_left = $columns_count; foreach ($column_names as $column_name) { $query_formats .= $struct["columns"][$column_name]["format"]; $in_type = $struct["columns"][$column_name]["php"]; $out_type = $struct["columns"][$column_name]["sql"]; if ($struct["columns"][$column_name]["format"] == "%r") { $escape = false; } else { $escape = true; } $params_list[] = array('escape' => $escape, 'val' => $cast->PHPToSQL($data[$column_name], $in_type, $out_type)); if ($columns_left != 0) { $query_formats .= ", "; $columns_left--; } } $query_formats .= ")"; } else { $columns_left = $columns_count; $cast = new FOX_cast(); $query_formats .= "("; foreach ($column_names as $column_name) { $query_formats .= $struct["columns"][$column_name]["format"]; $in_type = $struct["columns"][$column_name]["php"]; $out_type = $struct["columns"][$column_name]["sql"]; if ($struct["columns"][$column_name]["format"] == "%r") { $escape = false; } else { $escape = true; } $params_list[] = array('escape' => $escape, 'val' => $cast->PHPToSQL($data->{$column_name}, $in_type, $out_type)); if ($columns_left != 0) { $query_formats .= ", "; $columns_left--; } } $query_formats .= ")"; } // Build the UPDATE columns string // ###################################################### $columns_left = $columns_count; foreach ($column_names as $column_name) { $update_columns_string .= $column_name . " = " . $struct["columns"][$column_name]["format"]; $in_type = $struct["columns"][$column_name]["php"]; $out_type = $struct["columns"][$column_name]["sql"]; $cast = new FOX_cast(); if ($struct["columns"][$column_name]["format"] == "%r") { $escape = false; } else { $escape = true; } if (is_array($data)) { // Handle data passed as array $params_list[] = array('escape' => $escape, 'val' => $cast->PHPToSQL($data[$column_name], $in_type, $out_type)); } else { // Handle data passed as object $params_list[] = array('escape' => $escape, 'val' => $cast->PHPToSQL($data->{$column_name}, $in_type, $out_type)); } if ($columns_left != 0) { $update_columns_string .= ", "; $columns_left--; } } $query = "INSERT INTO " . $this->base_prefix . $struct["table"] . " (" . $insert_columns_string . ") VALUES " . $query_formats . " ON DUPLICATE KEY UPDATE " . $update_columns_string; // Merge all return data into an array // ############################################################### $result = array('query' => $query, 'params' => $params_list); return $result; }