i am trying to insert data to database but it removing braces'{}' while inserting i am using this code.
<pre><code>
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
$aa['alt']="happy alt";
$aa['title']="happy title";
$sldata=serialize($aa);
$sql="Insert into test(pval) values('".$sldata."')";
echo $sql;
db_query($sql);
</pre></code>
my db structure is as
<pre><code>
CREATE TABLE IF NOT EXISTS `test` (
`sl` int(11) NOT NULL AUTO_INCREMENT,
`pval` text NOT NULL,
PRIMARY KEY (`sl`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
</pre></code>
suggest me what is wrong here..
Drupal uses {} arround the tables names, to be able to do some manipulations on those names -- like prefix them, if you have configured it to do so.
So, you must not use {} in your query -- except arround tables names, of course.
Instead of brutaly injecting your serialized-string into the SQL query, you must use place-holders in it -- and pass the corresponding values to db_query(), which will take care of escaping what has to be :
$sldata = serialize($aa);
$sql = "insert into {test} (pval) values('%s')";
db_query($sql, $sldata);
Here :
As the pval field is a string in database, I used a %s place-holder
And the first value passed to db_query() (after the SQL query itself, of course) will be injected by drupal, to replace that first (and only, here) placeholder.
And, for more informations, you might want to take a look at Database abstraction layer.
instead of just serialize, you could base64_encode to bypass curlies being a problem.
http://php.net/manual/en/function.base64-encode.php
base64_encode(serialize($aa));
Then on the retrieving side of the data
unserialize(base64_decode($db_data));
Related
I'm having trouble with this snippet of code, and can't find any errors:
$query = "CREATE TABLE ? (? INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(?), ? VARCHAR(30), ? VARCHAR(50), ? TIMESTAMP, ? VARCHAR(50), ? DECIMAL(15, 2), ? DECIMAL(3, 2), ? VARCHAR(255))";
$array = array($table_name, $id, $id, $a_title, $c_title, $date_updated_title, $s_title, $ds_title, $ps_title, $u_title);
try {
$results = db_query($db, $query, $array); // db_query() is my PDO function to query the database. This function works fine elsewhere.
echo($table_name . " create successfully!");
} catch (PDOException $e) {
echo('<br />Could not create table "' . $table_name . '".');
return false;
error($e); //error() is my function to write errors to my log, and works fine elsewhere.
}
When I run this in my browser, it returns my caught exception 'Could not create table "name".' However, I don't see any error in my log, so I don't know if it's a syntax issue, or what.
When I take the query itself, and replace the question marks with the actual values, and dump it in PHPMyAdmin, it creates the table fine. I'm not really sure what the issue is here. I've had reasonable success with PDO on another site, but I'm still relatively new. Any ideas?
Thanks for the help!
[Edit] I've since tried using this query:
"CREATE TABLE $a_title (? INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(?), ? VARCHAR(30), ? VARCHAR(50), ? TIMESTAMP, ? VARCHAR(50), ? DECIMAL(15, 2), ? DECIMAL(3, 2), ? VARCHAR(255))";
I've tried with both single and double quotes. I also removed the $table_name variable from the array. Still getting a syntax error, and not sure why.
Comment from #DCoder is correct. You can use a query parameter only in place where you could normally put a single string literal, date literal, or numeric literal.
You can't use a query parameter for:
Table names
WRONG: SELECT * FROM ?
Column names
WRONG: SELECT * FROM table WHERE ? = 1234
Lists of values
WRONG: SELECT * FROM table WHERE column IN (?)
Though you could use IN() with a list of parameter placeholders, one for each scalar value.
SQL operators, expressions, or keywords
WRONG: SELECT * FROM table WHERE column ? 'value' AND ? ORDER BY column ?
For those cases, if you want dynamic content to become part of your query, the content must be part of the query before you call prepare().
But this means that you're back to interpolating variables into SQL query strings, which we are told is a no-no for its SQL injection risk.
The solution is to use filtering and whitelisting to make sure that the content doesn't contain some unsafe content. For example, if it's a dynamic table name, strip out anything but characters you know you want to keep, and then also delimit the table name just in case someone names their table a reserved word like "table" or "order" or something.
$table = preg_replace("/[^\w]/", "", $table);
$sql = "CREATE TABLE `{$table}` ( ... )";
Re your comment:
Yes, column names are off limits as well. As I said at the top, parameters are only for scalar values.
You also need to learn the appropriate usage of the three different types of quote marks.
What is the difference between single and double quotes in SQL?
Do different databases use different name quote?
I am using PostgreSQL 9.1.11.
I need to return result of SELECT to my php script. The invocation in php is like this:
$res = $pdb->getAssoc("SELECT * FROM my_profile();");
The class code to illustrate what is going on in php
public function getAssoc($in_query) {
$res = pg_query($this->_Link, $in_query);
if($res == FALSE) {
return array("dberror", iconv("utf-8", "windows-1251", pg_last_error($this->_Link)));
}
return pg_fetch_all($res);
}
Next comes my function in Postgres. I fully re-create database by dropping in a script when I update any function. (The project is in the early stage of development.) I have little to no experience doing stored procedures.
I get this error:
structure of query does not match function result type
CONTEXT: PL/pgSQL function "my_profile" line 3 at RETURN QUERY )
Trying to write:
CREATE FUNCTION my_profile()
RETURNS TABLE (_nick text, _email text) AS $$
BEGIN
RETURN QUERY SELECT (nick, email) FROM my_users WHERE id = 1;
END;
$$
LANGUAGE 'plpgsql' SECURITY DEFINER;
Table structure is:
CREATE TABLE my_users(
id integer NOT NULL,
nick text,
email text,
pwd_salt varchar(32),
pwd_hash character(128),
CONSTRAINT users_pk PRIMARY KEY (id)
);
When I return 1 column in a table the query works. Tried to rewrite procedure in LANGUAGE sql instead of plpgsql with some success, but I want to stick to plpgsql.
The Postgres 9.1.11, php-fpm I am using is latest for fully updated amd64 Debian wheezy.
What I want to do is to return a recordset containing from 0 to n rows from proc to php in an associative array.
This part is incorrect:
RETURN QUERY SELECT (nick, email) FROM my_users WHERE id = 1;
You should remove the parentheses around nick,email otherwise they form a unique column with a ROW type.
This is why it doesn't match the result type.
#Daniel already pointed out your immediate problem (incorrect use of parentheses). But there is more:
Never quote the language name plpgsql in this context. It's an identifier, not a string literal. It's tolerated for now since it's a wide-spread anti-pattern. But it may be considered a syntax error in future releases.
The SECURITY DEFINER clause should be accompanied by a local setting for search_path. Be sure to read the according chapter in the manual.
Everything put together, it could look like this:
CREATE FUNCTION my_profile()
RETURNS TABLE (nick text, email text) AS
$func$
BEGIN
RETURN QUERY
SELECT m.nick, m.email FROM my_users m WHERE m.id = 1;
END
$func$
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public, pg_temp;
Replace public whit the actual schema of your table.
To avoid possible naming conflicts between OUT parameters in RETURNS TABLE ... and table columns in the SELECT statement I table-qualified column names with the given alias m.
In my database design, I tend to store some variable that is meant to be acting as a ROLE or TYPE as SMALLINT.
For example:
CREATE TABLE `house` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` smallint(11) NOT NULL,
And in PHP, I do:
define('HOUSE_SMALL_TYPE', '0');
define('HOUSE_MEDIUM_TYPE', '1');
So in PHP, in SELECT queries I do:
$this->db->query("SELECT * FROM house
WHERE type = ?;", HOUSE_SMALL_TYPE);
My questions are:
In the PHP part, is there is a better way to do this?
In the MySQL itself, does MySQL also has global define functionality (like the define in PHP)?
I also want to do kind of
SELECT * FROM house WHERE type = HOUSE_SMALL_TYPE;
in MySQL query.
My purpose is that when I do SELECT in MySQL, no way I'm going to keep mapping the value 0,1,2 with its real meaning. Just convenience for viewing the tables values, without changing the structure table and fields.
Since MySQL 5.5 it's not possible to set a global user-defined variable.
A work-around might be to create a stored procedure that would return what you need.
DROP PROCEDURE IF EXISTS HOUSE_SMALL_TYPE;
DELIMITER //
CREATE PROCEDURE HOUSE_SMALL_TYPE ()
BEGIN
SELECT 0;
END//
DELIMITER ;
and then call it.
CALL HOUSE_SMALL_TYPE();
The DROP statement is required in order to be able to modify it.
IMHO, MySQL has a huge gap in this area, apparently in the latter versions. One alternative might have been to resort to setting OS environment variables, but how such values can be retrieved from within MySQL, I've been unable to see.
There's a whole page here: https://dev.mysql.com/doc/refman/5.0/en/setting-environment-variables.html teaching us how to "set" OS environment variables in the shell, but not a word on actually calling such variables in MySQL.
As another workaround, using a FUNCTION might be considered more lightweight than a STORED PROCEDURE, like so:
CREATE DEFINER=`root`#`localhost` FUNCTION `DEFAULT_COUNTRY_CODE`() RETURNS CHAR(4)
DETERMINISTIC
RETURN '+234';
Elsewhere in your query, you can then do:
SELECT CONCAT(DEFAULT_COUNTRY_CODE(), "-", telephone) FROM contacts WHERE CountryCode = "NGA"
Your approach is fine, if you want to see the values in MySQL instead of 1, 2, 3 etc. then consider this:
define('HOUSE_SMALL_TYPE', 'HOUSE_SMALL_TYPE');
define('HOUSE_MEDIUM_TYPE', 'HOUSE_MEDIUM_TYPE');
Then in MySQL you can use:
SELECT * FROM house WHERE type = 'HOUSE_SMALL_TYPE';
You just need to remember that you cannot just jam any value you like into house.type without having support for it in PHP.
Even better consider this:
class HouseType {
const SMALL = 'SMALL';
const MEDIUM = 'MEDIUM';
}
or
class House {
const TYPE_SMALL = 'SMALL';
const TYPE_MEDIUM = 'MEDIUM';
}
because then you can use HouseType::SMALL or House::TYPE_SMALL in your PHP code rather than using a global define. By doing this you may benefit from code completion in some IDE's.
Since MySQL 5.5 it's not possible to set a global user-defined variable, another workaround could be helping table like
create table glob_var(key varchar(10) unique not null, val varchar(10) not null);
I suggest using MySQL variables:
SET HOUSE_SMALL_TYPE = 0;
SET HOUSE_MEDIUM_TYPE = 1;
Then, in your queries you may use these variables:
SELECT * FROM house WHERE type = #HOUSE_SMALL_TYPE;
This method defines session variables:
If you change a session system variable, the value remains in effect
until your session ends or until you change the variable to a
different value. The change is not visible to other clients.
If you want to define global MySQL variables (available to all sessions):
SET GLOBAL HOUSE_SMALL_TYPE = 0;
SET GLOBAL HOUSE_MEDIUM_TYPE = 1;
To indicate explicitly that a variable is a global variable, precede
its name by GLOBAL or ##global.. The SUPER privilege is required to
set global variables.
Documentation:
SET statement
Using system variables
User-defined variables
I'm trying to create a dynamic form builder. Therefore PHP gets a set of names from a database and creates a new table with those names as column names. This works quite well until one or more names are integer (for ex. '12345'). Then the script fails.
How can I force PHP of MySQL to give numeric table names?
Here is a piece of the code (its still a draft):
$slaop = 'id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)';
require_once 'dbconnect.php';
$connector = new DbConnector();
$result = $connector->query( 'SELECT * FROM '.$form.' ORDER BY rang' );
while ($opslaan = $connector->fetchArray($result)){
$slaop .= ', ';
$slaop .= $opslaan['tekstid'];
$slaop .= ' TEXT';
}
echo $slaop;
// OPSLAAN
$formnaam = $_GET['welkform'];
require_once 'dbconnectsave.php';
$connector = new DbConnectorSave();
$connector->query('CREATE TABLE '.$formnaam.'('.$slaop.')')
or die(mysql_error());
$opslaan['tekstid']; is the part where the text of integer are called.
Does anyone have an idea?
Why not prefix all tables with the form name? Then integers don't matter...
As others have noted, this may not be a good idea.
However, you can still do it if the column name is surrounded in backticks. Here's a couple of MySQL examples:
create table abc (id int, 123 int); -- fails
create table abc (id int, `123` int); -- succeeds
How can i force php of mysql to give numeric table names?
May be you can force your application not to use such field names?
And also change the whole design as well, without employing dynamically created tables, and use more usual approach of storing table structure in some table?
Use a prefix that starts with a letter for your column names.
I'm used to use mysql table prefixes in my php scripts. Yet triggers and routines sometimes are very useful too. Ok. Let's say i have a table: 'pre_customers'. And a procedure sth like
CREATE FUNCTION `get_all_clients`() RETURNS int(11)
BEGIN
DECLARE sum INT ;
SELECT COUNT(id) INTO sum FROM pre_customers ;
RETURN sum;
END
No big deal, just for example. And there is also a constant
<?php
define( 'DB_PREFIX', 'pre_' ) ;
It's being used for changing table prefixes. If i need to make an sql-request in the script i make it like this
$query = "SELECT * FROM " . DB_PREFIX . "customers" ;
$result = mysql_query( $query ) ;
...
Alright, but if i want to change this prefix in the php-script along with the table names it's gonna ruin all stored routines and triggers, they still will apply to 'pre_customers' table. So the question is is there a common practice how normally programmers solve this problem.
So the question is is there a common practice how normally programmers solve this problem.
Create a dump
Create some kind of template using that dump, with pre_ replaced with %db_prefix%
When you need to change prefix - replace prefix in the template and import it to mysql