Perplexed here.... This code:
$qry = sprintf("INSERT INTO news_sites_homepage_grab
VALUES ('', %d, '%s', NOW(), NOW())",
$site_id, mysql_real_escape_string($html));
...is executed in a loop where $html changes every time. This code executes once but the next time, the script simply dies. No warnings/errors, nothing. $html is a string representing a webpage so it could be very long. I have upped the memory limit in PHP to 32M and set max_allowed_packet in MySQL to 16M but nothing.
Anyone have any ideas? Thanks!
UPDATE: Here is the function that is called within a loop.
function save_html($site_id, $html) {
global $db;
try {
$qry = sprintf("INSERT INTO site_grab VALUES ('', %d, '%s', NOW(), NOW())",
$site_id,
mysql_real_escape_string($html));
$db->insert($qry);
}
catch(Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
return;
}
My recommendation would be to forgo troubleshooting this issue and switch to PDO. It supports prepared statements, which aren't vulnerable to SQL injection when you use parameters and are much more performant for repeated queries.
Here's a simple refactoring of your function, which assumes $db holds a PDO instance:
function save_html($site_id, $html) {
global $db;
static $insert = Null;
if (isnull($insert)) {
/* explicitly name the columns, in case you later add more to the table
or change their order. I'm also guessing `id` is auto-incrementing,
so I'm leaving it out.
*/
$insert = $db->prepare("INSERT INTO site_grab (sid, site_text, date_added, date_modified) VALUES (?, ?, NOW(), NOW())");
}
try {
$insert->execute(array($site_id, $html));
} catch(Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
return;
}
If date_added has type TIMESTAMP, you can set its default value to CURRENT_TIMESTAMP and leave it out of the insert. Alternatively, add an ON UPDATE CURRENT_TIMESTAMP property to the date_modified column, which means you don't need to explicitly set the field when you update a row. If inserting is going to be more common than updating, do the former; otherwise, do the latter.
You could also store prepared statements in an object so they're accessible from multiple functions and replace the global $db with some sort of service locator (the simplest way is to use a static function or property of some class) or use dependency injection (read "Inversion of Control Containers and the Dependency Injection pattern").
I preffer using PDO and prepared statements but to (try to) answer your question try adding $db as the link identifier to mysql_real_escape_string() function.
Does that help? If not, try echoing the output of the mysql_error() function.
Sorry for the lack of formating, I'm mobile ATM.
Related
I have to deal with large mysql DB. Sql queries with lot of calculations (in select clause) and several kind of conditions in where clauses. So, I decided to use row/direct sql queries to deal with DB by using $db = ConnectionManager::getDataSource('default');
If I use this, how I prevent sql injection in mysql query? "mysql_real_escape_string" no longer exists. Is there any way to use PDO within CakePHP?
You can use this in your controller (or component)
// Initiate PDO connection
$this->_pdocon = $this->WhateverYourModel->getDataSource()->getConnection();
try {
// Select Query
$company = "What";
$stmt = $this->_pdocon->prepare('SELECT * FROM `agents` WHERE `company` LIKE :company LIMIT 2');
$stmt->bindValue(':company', $company, PDO::PARAM_STR);
// Start transaction
$this->_pdocon->begin();
// Loop through the events
if( $stm->execute() ) {
while ($row = $stmt->fetchAll(PDO::FETCH_ASSOC)) {
$stmt2 = $this->_pdocon->prepare("INSERT INTO `company`
(`id`, `name`, `identityno`, `modified`, `created`)
VALUES
(NULL, :name, :identityno, NOW(), NOW())");
$stmt2->bindValue(':name', $row['name'], PDO::PARAM_STR);
$stmt2->bindValue(':identityno', $row['id'], PDO::PARAM_INT);
$stmt2->execute();
}
}
// Commit transaction
$this->_pdocon->commit();
// Get last insert Id
$row_id = $this->_pdocon->lastInsertId();
var_dump($row_id);
} catch (PDOException $e) {
// Rollback transaction
$this->_pdocon->rollback();
echo "! PDO Error : " . $e->getMessage() . "<br/>";
}
This is what I ended-up. Using PDO has been solved thousands of issues. Now the system is fast and no memory exhaust error. And I can not putting all issues, errors what I got, in my question. It's good to giving direct answer rather trying to changing questions in here!
A large part of the point of cakePhp is not to do this. Therefore I would recommend not doing this.
Cakephp has a its own implementation for accessing a DB and you should use it if at all possible. Is there a particular reason you want to go around it?
if you realy want to, you can still use mysqli but I cant recommend it.
basically I am trying to implement a function in one of my PHP classes that makes an entry into a junction table for a many to many relationship.
This is the method here:
public function setTags($value, $id){
global $db;
$tags = $value;
$query .= "DELETE FROM directorycolumntags
WHERE directorycolumn_id = $id; ";
foreach($tags as $tag){
$query .= "INSERT INTO directorycolumntags (directorycolumn_id, tag_id)
VALUES (".$id.",".$tag.");";
}
mysql_query($query);
}
The SQL is produces works fine, as I've echoed it and manually executed it via phpMyAdmin. However, If I leave it as above, the data is never inserted. Does anyone know why this might be happening?
This is the sql it is generating which works fine when I type it manually in:
DELETE FROM directorycolumntags WHERE directorycolumn_id = 178;
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,29);
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,30);
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,32);
The old, unsafe, deprecated mysql_* extension never supported multiple queries. You could, conceivably do this using the mysql replacement extension: mysqli_*, which has the mysqli_multi_query function.
Personally, I'd not use this approach, though. I'd do what most devs would do: use a prepared statement in a transaction to execute each query safely, and commit the results on success, or rollback on failure:
$db = new PDO(
'mysql:host=127.0.0.1;dbname=db;charset=utf8',
'user',
'pass',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
try
{
$db->beginTransaction();
$stmt = $db->prepare('DELETE FROM tbl WHERE field = :id');
$stmt->execute(array(':id' => $id));
$stmt = $db->prepare('INSERT INTO tbl (field1, field2) VALUES (:field1, :field2)');
foreach ($tags as $tag)
{
$stmt->execute(
array(
':field1' => $id,
':field2' => $tag
)
);
$stmt->closeCursor();//<-- optional for MySQL
}
$db->commit();
}
catch (PDOException $e)
{
$db->rollBack();
echo 'Something went wrong: ', $e->getMessage();
}
Going slightly off-topic: You really ought to consider using type-hints. From your code, it's clear that $values is expected to be an array. A type-hint can ensure that the value being passed is in fact an array. You should also get rid of that ugly global $db;, and instead pass the connection as an argument, too. That's why I'd strongly suggest you change your function's signature from:
public function setTags($value, $id){
To:
public function setTags(PDO $db, array $value, $id)
{
}
That way, debugging gets a lot easier:
$instance->setTags(123, 123);//in your current code will not fail immediately
$instance->setTags($db, [123], 123);//in my suggestion works but...
$instance->setTags([123], null, '');// fails with a message saying argument 1 instance of PDO expected
http://docs.php.net/mysql_query says:
mysql_query() sends a unique query (multiple queries are not supported) to the currently active database on the server that's associated with the specified link_identifier
If you can use mysqli perhaps this interest you: mysqli.multi-query
Executes one or multiple queries which are concatenated by a semicolon.
you can not run multiple quires using mysql_query, try to modify your function like this. It would be better if you use mysqli or pdo instead of mysql because soon it will deprecated and it would not work on newer version of php
public function setTags($value, $id){
global $db;
$tags = $value;
mysql_query("DELETE FROM directorycolumntags WHERE directorycolumn_id = $id");
foreach($tags as $tag){
mysql_query("INSERT into directorycolumntags (directorycolumn_id, tag_id) VALUES (".$id.",".$tag.")");
}
}
I have this query:
mysql_query("INSERT INTO `63_Activity` (`username`, `time`) VALUES (`$usernann2`, `$date`)");
However, it doesn't do anything. Even when I tried correcting the variables to
". $variable ."
I checked the variables.
I copied the little line of code from somewhere it works.
The database and tables are existing.
I just thought I had things under control, then that happened -.-
Thank you in advance.
PS: I tried adding or die() - but no error. Nothing.
Values need to be in single quotes ('), not backticks (`)
mysql_query("INSERT INTO `63_Activity` (`username`, `time`) VALUES ('$usernann2', '$date')");
You should also make sure you're sanitizing your inputs, as well as preferably not using the mysql_ functions in place of mysqli_
You would be better off using Paramaterized queries as in the following example:
<?php
try {
$usernann2 = "whateverUsernameFits";
$date = new DateTime('2000-01-01');
$stmt = $this->db->prepare ( "INSERT INTO 63_Activity (username, time) VALUES (:usernann2, :date)");
$stmt->bindParam ( ':usernann2', $usernann2 );
$stmt->bindParam ( ':date', $date );
$stmt->execute ();
}catch ( PDOException $e )
{
throw new Exception ( $this->db->errorInfo () . 'Problem inserting object ' );
} catch ( Exception $e ) {
throw new \Exception ( 'Problem inserting object ' );
}
?>
Bound parameters are a staple in preventing SQL Injection attacks. The exceptions thrown would give you a clue as to what might be the problem in your query if there is one. I normally check the query first to make sure it's working with real values. From there it is a process of elimination.
PS. https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet for more information on SQL Injection. You should also be able to find some excellent information and questions here on Stackoverflow regarding SQL Injection.
try to put the query in a variable and echo it, and see if anything wrong, try to run it on php my admin also
I am trying PDO transactions for the first time. The below code doesnt work. the email address we are trying to insert has a duplicate so it should fail. It does give me an error. but the first insert get inserted into the DB and it doesnt roll back. I know rollback work cuase if i move PDO::rollBack into the Try{ before commit, it does roll back. I think the problem is its not catching the error, therefore not calling PDO::rollBack. Any ideas?
try {
PDO::beginTransaction();
$sql = "INSERT INTO .`tblUsersIDvsAgencyID` (`id`, `agency_id`) VALUES (NULL, :agencyID)";
$STH = $this->prepare($sql);
$STH->bindParam(':agencyID', $AgencyUser['agency_id']);
$STH->execute();
$userID = parent::lastInsertId();
$sql = "INSERT INTO `tblUsersEmailAddress` (`id`, `user_id`, `email_address`, `primary`, `created_ts`, `email_verified`) VALUES (NULL , :userID , :EmailAddress , '1', CURRENT_TIMESTAMP , '0' )";
$STH = $this->prepare($sql);
$STH->bindParam(':userID', $userID);
$STH->bindParam(':EmailAddress', $email_address);
$STH->execute();
PDO::commit();
echo 'Data entered successfully<br />';
}
catch(PDOException $e)
{
/*** roll back the transaction if we fail ***/
PDO::rollBack();
echo "failed";
}
PDO::beginTransaction() is not a static method. From your question, it looks like you're extending the PDO class. I wouldn't do that as I doubt you're adding anything significant to the base class. Instead, you should the set the PDO connection as a class property.
For example
class ParentClass
{
/**
* #var PDO
*/
protected $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
// Make sure PDO is set to throw exceptions
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
class ChildClass extends ParentClass
{
public function insertStuff()
{
$this->dbh->beginTransaction();
try {
// do stuff
$this->dbh->commit();
} catch (PDOException $e) {
$this->dbh->rollBack();
throw $e;
}
}
}
I'm just going to start by quoting the docs:
Beware: Some MySQL table types (storage engines) do not support transactions. When writing transactional database code using a table type that does not support transactions, MySQL will pretend that a transaction was initiated successfully. In addition, any DDL queries issued will implicitly commit any pending transactions.
Your problem may be expected behavior. Additionally:
beginTransaction is not static. (I repeat Phil's statement that you should not be extending PDO).
Call $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
You never call closeCursor on your statement (this will often cause problems). (Phil points out that it is not explicitly necessary in this case. It is still best practice though).
Using bindParam does not yield any benefit for the userID variable as you are using it (a locally defined variable which is not re-used).
I am going to use a small SQLite database to store some data that my application will use.
I cant however get the syntax for inserting data into the DB using PHP to correctly work, below is the code that i am trying to run:
<?php
$day = $_POST["form_Day"];
$hour = $_POST["form_Hour"];
$minute = $_POST["form_Minute"];
$type = $_POST["form_Type"];
$lane = $_POST["form_Lane"];
try
{
$db = new PDO('sqlite:EVENTS.sqlite');
$db->exec("INSERT INTO events (Day, Hour, Minute, Type, Lane) VALUES ($day, $hour, $minute, $type, $lane);");
$db = NULL;
}
catch(PDOException $e)
{
print 'Exception : '.$e->getMessage();
}
?>
I have successfully created a SQLite database file using some code that i wrote but i just cant seem to insert data into the database.
You can't simply insert strings inside your query like that. Take a look at PDO::quote() and prepared statements.
there's nothing syntactically wrong with this, unless one of the vars ($day, $hour, etc) returns an empty string.
$db->exec("INSERT INTO events (Day, Hour, Minute, Type, Lane) VALUES ($day, $hour, $minute, $type, $lane);");
having said that, i'd be more worried about sql injection because you're applying $_POST variables directly into an sql statement without validation.
You should rather use parametrized queries. Try this:
$db = new PDO('sqlite:EVENTS.sqlite');
$stmnt = $db->prepare("INSERT INTO events (Day, Hour, Minute, Type, Lane) VALUES (:day, :hour, :minute, :type, :lane);");
$stmnt->execute( array('day'=>$day,'hour'=>$hour, 'minute'=>$minute, 'type'=>$type, 'lane'=>$lane) );
$db = NULL;
You should explicitly commit transactions after the modifying DML statements (INSERT, DELETE, UPDATE) with COMMIT;.