How does $this->db->trans_status() work in codeigniter transactions? - mysql

How exactly does $this->db->trans_status() in CodeIgniter understand that whether the queries in the transaction were successful or not?
Source: http://codeigniter.com/user_guide/database/transactions.html
$this->db->trans_begin();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');
if ($this->db->trans_status() === FALSE){
$this->db->trans_rollback();
}
else{
$this->db->trans_commit();
}
Am using MySQL as the underlying database

SQL has a statement for START TRANSACTION one COMMIT and one for ROLLBACK.
Your database driver and/or abstraction layer doesn't have to send the entire list at once:
$query_string = '
START TRANSACTION;
SELECT something FROM somewhere;
UPDATE something SET something.we_have = something.else;
COMMIT;';
$dba->execute($query_string);
They can be sent individually and the driver and/or abstraction layer can wait for the query to execute and return an SQL STATUS.
$query_string = 'START TRANSACTION;';
$dba->execute($query_string);
$query_string = 'SELECT something FROM somewhere;';
$dba->execute($query_string);
$query_string = 'UPDATE something SET something.we_have = something.else;';
$dba->execute($query_string);
$status = $dba->get_status();
if($status)
$query_string = 'COMMIT;';
else // darn our update must have failed
$dba->execute($query_string);
And based on that status you can decide weather to COMMIT or ROLLBACK.
Of course this implies that the overall time spent by your script in connecting to the DB is bigger than if it would've just shoved the entire string down the pipe in one connection.

This is a mess:
if($status)
$query_string = 'COMMIT;';
else // darn our update must have failed
$dba->execute($query_string);
Maybe you want:
if($status)
$query_string = 'COMMIT';
else // darn our update must have failed
$query_string = 'ROLLBACK';
$dba->execute($query_string);

Related

how to inject sql in login process

I've received an old application which completely lacks user input sanitization and is vulnerable to sql injection. To prove gravity of the situation i need to give client an example and what can be better to scare him than the login process. I've tried standard techniques but the problem with them is that they return multiple rows and due to nature of the code it returns an error instead of logging him in. What sql should i inject so that only a single row is returned and the execution reaches "return $access" line in order to pass the value of this "access" column to code calling this login function. The request is made via POST method and magic quotes are off on the server. Please let me know if you need any other information.
function login($username, $pw)
{
global $dbname, $connection, $sqluser, $sqlpw;
$db = mysql_connect($connection,$sqluser,$sqlpw);
mysql_select_db($dbname);
if(!($dba = mysql_query("select * from users where username = '$username' AND password = '$pw'"))){
printf("%s", sprintf("internal error5 %d:%s\n", mysql_errno(), mysql_error()));
exit();
}
$row = mysql_fetch_array($dba);
$access = $row['access'];
if ($access != ''){
return $access;
} else {
return "error occured";
}
mysql_close ($db);
}
Note: it turns out that magic_quotes_gpc is turned on and the php version is 5.2.17
Thanks
Starting with the goal query:
SELECT *
FROM users
WHERE username = '' OR '1'='1'
AND password = '' OR 1=1 LIMIT 1;#'
We get username is ' OR '1'='1 and password is ' OR 1=1 LIMIT 1;#
It depends what values the login function is called with. If there's sanitation before passing it to the function it might actually be safe. However it's better to filter it right before the query so you can see that your built query is safe.
However if you have something like this:
login($_POST['user'], $_POST['pass']);
In that case just put foo' OR 1=1 OR ' in the user field in the login form :)

Mysql delete query won't work on lamp stack

I am doing a project work on php. During my work every single query work smoothly. But when I want to delete any object using it won't delete ...
Here's my php code
<?php
//delete item
if(isset($_GET['deletecat'])){
$id_to_delete = $_GET['deletecat'];
$sql = mysql_query("DELETE FROM `category` WHERE `Category_id`=$id_to_delete LIMIT 1") or die('Error: Could not delete.');
}
else{
header('location: category.php');
exit();
}
?>
and after that I only get the error message.
GET value is OK. And on my phpmyadmin this SQL running OK. But there's a pop up message appear when I want to delete any object. what can I do now?
there's a few layers where you could be having issues: with the db connection, the query, or the data which you are sending.
also, you are not filtering for " and ' marks so you could be in trouble there, and you're not ensuring that your id is a number so your sql could also be failing there.
but, you can figure that out with a few adjustments to your code.... you can insert some diagnostics into your code to see what mysql is reporting the error as and get a better idea of how to fix it.
note that it is [generally recommended][1] to use mysqli extension instead of mysql extension, but irregardless, here's sample code with the extension you are currently using
hope this helps!
<?php
if ( isset($_GET['deletecat'])) {
#dbh -> database resource.
$dbh = mysql_connect()
#mysql_connect returns false if it fails. capture error and echo to output.
if (!$dbh) {
die("Could not connect to database server: ".mysql_error()."\n");
#if using mysqli use mysql_connect_error() instead
}
#never trust input. use an escape function.
$id_to_delete = mysql_real_escape_string($_GET['deletecat'],$dbh);
#force $id_to_delete to be treated as a number, or make it safer in your sql.
#i used the latter method below.
$sql = "DELETE FROM `category` WHERE `Category_id` = '$id_to_delete' LIMIT 1");
#mysql_query returns false on failure
$result = mysql_query($sql,$dbh);
#on failure catch the error and display the exact contents of 'deletecat' in a web-friendly way.
if (!$result) {
$error=mysql_error($dbh);
die ("Error: Could not delete '"
.htmlentities(print_r($_GET['deletecat'],true)).". Error: $error\n"
);
}
#if we did not trigger die() above we are ok.
header('location: category.php');
exit();
}
?>
:
[1]: see warning at http://php.net/manual/en/function.mysql-connect.php
You should escape the GET variable first to avoid any SQl injection attacks as already said by deceze. Then, you should understand that the message given by phpmyadmin is a confirmation if you need to execute the delete query. you can use mysql_real_escape_string($value) to escape but as php vendor says, this function will be removed very soon and is currently deprecated.
bye..

Perl fetch without execute error - at end of execution

My current perl code is running through all of the rows of the database query and then throwing a
DBD::mysql::st fetchrow_hashref failed: fetch() without execute() at ./recieveTxn.cgi
line 168.
At the end. It almost is like there's something that's not telling the loop to stop at the end of the rows, but I have written it just as the others.
So for example: The query would pull up
shortcode1
shortcode2
shortcode3
then throw the error here
$sql = "
SELECT
aPI.folder AS aPIfolder,
aPI.rowNum AS aPIrowNum,
hasInput,
evalCode
FROM
aPersonalItems as aPI
LEFT JOIN
pItems_special_inputs as SI
ON
aPI.folder = SI.folder AND
aPI.rowNum = SI.rowNum
WHERE
hasInput=1 AND
aPI.folder='$FORM{'folder'}'
ORDER BY
aPI.rowNum
";
$sth = $dbh->prepare( $sql );
$sth->execute();
my ($shortcoderow, $row);
my $shortcodeSQL = "
SELECT
*
FROM
pItemsShortCodes
WHERE
folder='$FORM{'folder'}'
ORDER BY
rowNum
";
my $shortcodeSTH = $dbh->prepare( $shortcodeSQL );
$shortcodeSTH->execute();
while( my $ref = $sth->fetchrow_hashref() ) {
my $shortCode;
my $isblank = 1;
my $rowNum = $ref->{'aPIrowNum'};
while(my $shortcodeRef = $shortcodeSTH->fetchrow_hashref())
#&& $rowNum == $shortcodeRef->{'rowNum'}) #line 168 above
{
$shortCode=$shortcodeRef->{'shortcode'};
print $shortCode."\n";
}
$shortcodeSTH->finish();
}
The problem is that you are processing more than one row from $sth.
Your code fetches a row from $sth, and then your code loops through every row from $shortcodeSTH, until there are no more rows. Then your code calls the finish() method on $shortcodeSTH. (Which is the normative pattern, since you've already fetched all the rows.)
Then, your code starts through the outer loop a second time, fetching a second row from $sth. When your code attempts to start through the $shortcodeSTH loop a second time, you've already fetched all of the rows and closed the statement handle. There aren't any more rows to retrieve. (The error returned would be different if you hadn't issued the call to the finish() method; the error message would be something about fetching past the end of the cursor, or already fetched last row, or something to that effect.)

How to tell if error occured in MySQL client script

I can't discover how to tell if an error occurred in a MySQL client script (after a couple of hours googling and reading the MySQL docs. I would expect there would be something like an error flag or error number that gets set when an error occurs and that you could test this with something like the following:
start transaction
error_flag = false; #just to be safe
...do some work...
... do some more work ...
if ( error_flag == true )
then
rollback
else
commit
;
What's the canonical was of doing this? Am I way off base thinking this approach would work?
Thanks in advancd
$result = mysql_query($query);
if (!$result) {
$errm = "[SQL" . mysql_errno() . "] " . mysql_error();
$this->rollback(); //implement your rollback
throw new Exception($errm);
}
this is the old mysql_* way. Please use pdo instead.

Query only working on PHPMyAdmin

I'm trying this query:
//connect;
$site = mysql_real_escape_string($_GET['site']);
$data = mysql_query("SELECT * FROM Items WHERE Site = '$site'");
while($row = mysql_fetch_array( $data ))
{
print $row['type'];
}
doesn't print anything, running SELECT * FROM Items WHERE Site = 'http://rollingstone.com/' from PHPMyAdmin returns one row.
I'm sure it must be something really basic, since I haven't got much experience with MySQL.
I'm trying it here btw: http://www.chusmix.com/game/insert/get-items.php?site=http://rollingstone.com/
What am I doing wrong?
Make sure $site actually contains something; doing a quick echo $site before your mysql_query() should tell you this. If it's empty, try print_r($_GET) to see if it's in the $_GET array. It should be, but it might not for some other reason; check any code above this snippet for stuff that modifies $_GET or $_REQUEST in any way.
To request data from a MySQL table, you need to connect to the server using mysql_connect(), then select the database with mysql_select_db(). PHP should throw errors, but to be sure put these lines at the top of your script:
error_reporting(E_ALL);
ini_set('display_errors', '1');
All errors will now be shown.
In addition, you can also test for how many rows that were returned using mysql_num_rows(). For example:
if(mysql_num_rows($data) !== false)
{
while(...)
{
...
}
}
else
{
echo "No rows";
}
Will echo No rows if there weren't any results from the query. This is all error detection code; the cause of your error isn't obvious, so a little investigation is necessary, using the above methods (and any more you can think of).
Have you called mysql_select_db('your_database_name'); on the connection first? Have you tried echoing out the SQL before it's executed to confirm that Site is what you expect it to be?
$query = sprintf("SELECT * FROM Items WHERE Site ='%s'",
mysql_real_escape_string($site));
$result = mysql_query($query);
Just to be on the safe side (avoid SQL Injections).