I used to code in the old way in php and been introduced through this forum to POO.
I'm rewriting a script that was in mysql into PDO. This script is to show the numbers and the names of connected members on a website. So far it only displays the number but not yet the list of names of connected members
that the script updated:
<?php
session_start();
if(isset($_SESSION['nom'])){
include('class.connect.php');
include('class.user.php');
$db = new DBEngine();
//verify if the name is already in the table
$log = $db->con->prepare('SELECT COUNT(nom) AS name FROM members_connected WHERE nom=?');
$log->execute(array($_SESSION['nom']));
$count = $log->fetchColumn(0);
$time = time();
if ($count == 0)
{
// the user is not in the new table, i add him
$log = $db->con->prepare('INSERT INTO members_connected (nom,timestamp) VALUES(?,?)');
$log->execute(array($_SESSION['nom'],$time));
}
//name already in the table, update the timestamp
else
{
$log = $db->con->prepare('UPDATE members_connected SET timestamp=? WHERE nom=?');
$log->execute(array($_SESSION['name'],$time));
}
//5 min earlier's timestamp
$timestamp_5min = time() - (60 * 5);
$log = $db->con->prepare('DELETE FROM members_connected WHERE timestamp < ?');
$log-> execute(array($timestamp_5min));
$log = $db->con->prepare('SELECT nom FROM members_connected');
$log->execute();
$row = $log->fetch(PDO::FETCH_ASSOC);
echo $count ;
//show the list of connected
if($count > 0)
{
$i=0;
while($count = $log->fetch(PDO::FETCH_ASSOC));
{
$i++;
echo $count['nom'];
if($i<$row)
{
//space between names
echo ',';
}
}
}
}
?>
`
Any thoughts please ?
try adding the following after your second include;
$db = new DBEngine();
Then in the code where you have
$this->db->con->prepare(...
change that to
$db->con->prepare(...
UPDATE
In answer to your second error, it looks like you need to set the variable types in your bindings.
e.g.
$log->bindParam(1, $_SESSION['name'], PDO::PARAM_STR, 25);
$log->bindParam(2, time(), PDO::PARAM_STR, 20);
Alternatively, you don't need to bind variables like that and you could pass them directly into the execute like so (which is what you have in your first query btw)
$log->execute(array($_SESSION['name'], time()));
Create a TimeStamp class that will fetch and update your database like so:
class TimeStamp
{
protected $db;
public $row_count;
public function __construct($db)
{
$this->db = $db;
}
// This should grab all users connected
public function Fetch($_user, $interval = '1')
{
// This is just checking a time range and collecting names
// You may want to make a new function that will then take the return list and query your user info table to get the user info
$connected = $this->db->con->prepare("select * FROM members_connected WHERE timestamp > DATE_SUB(NOW(), INTERVAL $interval MINUTE)");
$connected->execute(array($_user));
if($connected->rowCount() > 0) {
while($result = $connected->fetch(PDO::FETCH_ASSOC)) {
$users[] = $result;
}
}
// This should get the count
$this->row_count = (isset($users))? count($users):0;
// Return if users are available
return (isset($users))? $users:0;
}
public function Record($_user)
{
$connected = $this->db->con->prepare("INSERT INTO members_connected (nom, timestamp) VALUES (:nom,NOW()) ON DUPLICATE KEY UPDATE timestamp = NOW()");
$connected->bindParam(':nom', $_user);
$connected->execute();
}
}
include('class.connect.php');
include('class.user.php');
$db = new DBEngine();
if(isset($_SESSION['nom'])) {
// Start the timestamp, feed database
$u_check = new TimeStamp($db);
// Record into db
$u_check->Record($_SESSION['nom']);
// Check db, print users
$users = $u_check->Fetch($_SESSION['nom']);
print_r($users);
// Display count
echo "USERS: ".$u_check->row_count;
}
Related
I am new to php and struggling to get the data from a table in mysql and using it to connect to an ftp server. The table contains the external ip address of the ftp server, the base directory to change into and login credentials to use. I fetched the data from mysql and stored it in an array but while looping through it I get
php notice: trying to access array offset on type null.
Code:
$now = time();
$yesterday = $now - (24 * 60 * 60);
$date = date("Y-m-d", $yesterday);
if (isset($_GET['date'])) {
$date = $_GET['date'];
}
$startDate = "$date 00:00:00";
$endDate = "$date 23:59:59";
//$conn = &newEtConn();
$sql= "SELECT stager_usr, stager_pwd, stager_ip, basedir, view_direction from et_devices.cameras as a inner join et_params.stagers as b on a.stagerid = b.idstagers ";
$result = mysqli_query($conn,$sql);
$datas = array();
if (!$result) {
die ("table Connection problem");
}
if (mysqli_num_rows($result)>0){
while ($row = mysqli_fetch_assoc($result)){
$datas[] = $row;
}
print_r($datas);
}
if ($row!= "") {
foreach ($datas as $values) {
$ip_addr = $values['stager_ip'];
$login = $values['stager_usr'];
$password = $values['stager_pwd'];
$basedir = $values['basedir'];
if ($rows != "") {
$gotFtpConn = True;
$ftp_obj = ftp_connect($ip_addr, 21, 10) or $gotFtpConn = False;
if ($gotFtpConn) {
if (ftp_login($ftp_obj, $login, $passwd)) {
echo "could not connect" . $login;
return false;
}
return $newEtConn;
}
}
}
There are a few things that I don't like (and can improve)...
It looks like you intend to filter your database data based on a date, but then you never actually apply that value to the array. I'll help to clean up that process.
Your if ($row != '') check after the loop will always fail because the loop ONLY stops when $row becomes falsey.
The rest of your code looks like it only intends to process a single row in the result set (because it returns). I am going to assume that you have more conditional logic in your query's WHERE clause which ensures that only one row is returned -- otherwise, you shouldn't be using return in your loop.
$date = !empty($_GET['date']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_GET['date'])
? $_GET['date']
: date('Y-m-d', strtotime('yesterday'));
$sql = "SELECT stager_usr, stager_pwd, stager_ip
FROM et_devices.cameras AS a
JOIN et_params.stagers AS b ON a.stagerid = b.idstagers
WHERE DATE(a.some_datetime_column) = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param('s', $date);
$stmt->execute();
foreach ($stmt->get_result() as $row) {
$ftp = ftp_connect($row['stager_ip'], 21, 10);
if (!$ftp) {
throw new Exception('Failed to establish FTP connection');
}
if (!ftp_login($ftp, $row['stager_usr'], $row['stager_pwd'])) {
throw new Exception('Incorrect FTP login credentials');
}
return $ftp;
}
throw new Exception('FTP connection data not found');
If you experience a noticeable performance bottleneck with DATE() in your sql, then there are other techniques that may be faster, but they use longer/uglier syntax.
I'm creating a Reddit clone for web development class. Sorting posts by hotness is the final required thing for me to do.
What I'm struggling with, is binding hotness rating to database entry of given post on website. Because I'm already using a mysqli_query in the while loop, I can't start another query for adding hotness rating.
I read posts suggesting to use arrays but that would consume a lot of server resource since hotness would be calculated again on page refresh.
<?php
$link = mysqli_connect("localhost", "username", "password", "database");
if ($link === false) {
die("ERROR: Could not connect. " . mysqli_connect_error());
}
// this is just reddit's hotness algorithm
function hot($ups, $downs, $date) {
$s = $ups - $downs;
$order = log10(max(abs($s), 1));
if ($s > 0) {
$sign = 1;
} else if ($s < 0) {
$sign = -1;
} else {
$sign = 0;
}
$seconds = $date - 1134028003;
return round($sign * $order + $seconds / 45000, 2);
}
$query = "SELECT * from posts";
$result = mysqli_query($link, $query);
if($result) {
// goes through all posts for upvote/downvote values to calculate hotness
while ($row = mysqli_fetch_array($result)) {
$post_id = $row['post_id'];
$time_in_seconds = strtotime($row['timestamp']);
$hotness_rating = hot($row['upvotes'], $row['downvotes'], $time_in_seconds);
$hotness_query = 'UPDATE posts SET hotness=$hotness_rating WHERE post_id=$post_id';
// ideally this would add hotness to post's row in database
mysqli_query($link, $hotness_query);
}
} else {
echo mysqli_error($link);
}
?>
You should calculate "hotness" of topic on its update, such as up-vote, down-vote or new message and store it in database at that moment.
This will give you a "hotness" value in database without pointless* recalculations on every refresh and you could simply sort by "hotness".
These recalculations on every refresh is pointless, because if data isn't changed - you will get same result on every refresh and make useless updates to update to same value.
I have created the following function to fetch data from my database, but its capabilities are limited. Currently it can fetch one value at a time, which is fine for fetching the value of one column of one row, but as I progress with my work, I now want to be able to fetch multiple values in one call.
The Function:
function retrieve($value, $identifier = null) {
// Check if identifier is given
$identifier = (is_null($identifier)) ? "`ID` = '{$_SESSION["ID"]}'" : $identifier;
// Connect to the database
$connection = connect("limited");
// Pass query, get result and fetch value out of it
$query = "SELECT * FROM `users` WHERE $identifier";
$result = mysqli_query($connection, $query);
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_assoc($result);
return $data[$value];
}
mysqli_close($connection);
}
How I currently use it to fetch multiple values:
// Define variables
$x1 = retrieve("x1");
$x2 = retrieve("x2");
$x3 = retrieve("x3");
$x4 = retrieve("x4");
$x5 = retrieve("x5");
$x6 = retrieve("x6");
$x7 = retrieve("x7");
$x7 = retrieve("x8");
I have read other questions here on Stack Overflow, but none of them solves my problem as I use an optional parameter, which makes my life hard. For example, I thought of implementing the splat operator to allow unlimited parameters, but as I use the optional parameter $identifier, I can't make it into something like:
function retrieve($identifier = null, ...$value) {}
because it will use the first parameter as the identifier when I omit it.
I'm sure that regarding performance it would be better if I could fetch all the necessary values in one call of the function retrieve() instead of using it as shown above and that's why I would like to know:
How can I edit this function in order to fetch more values at once?
Calling it like so:
$x = retrieve($y);
$x1 = $y["x1"];
$x2 = $y["x2"];
...
EDIT:
Thanks to Manish Jesani for his help! I used his answer and modified to do exactly what I want. For anyone that may be interested in the future, here's the code:
function retrieve($value, $identifier = null) {
// Check if identifier is given
$values = array();
$identifier = (is_null($identifier)) ? "`ID` = '1'" : $identifier;
// Connect to the database
$connection = connect("limited");
// Pass query, get result and fetch value out of it
$query = "SELECT * FROM `users` WHERE $identifier";
$result = mysqli_query($connection, $query);
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_assoc($result);
if (is_array($value)) {
foreach($value as $_value) {
$values[$_value] = $data[$_value];
}
return $values;
}
else {
return $data[$value];
}
}
mysqli_close($connection);
}
You can call the function with as many parameters you want. Τo do this you have to use func_num_args() to get all of them, as shown below:
function retrieve() {
$args = func_num_args();
$query = "SELECT '".implode("','", func_get_args())."' FROM `users` WHERE $identifier";
$result = mysqli_query($connection, $query);
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_assoc($result);
return $data;
}
mysqli_close($connection);
}
You can call this function like this: $params = retrieve('x1','x2','x3').
Alternatively, you can retrieve them as variables list($x1, $x2, $x3) = retrieve('x1','x2','x3').
Please try this:
function retrieve($value, $identifier = null) {
// Check if identifier is given
$return = array();
$identifier = (is_null($identifier)) ? "`ID` = '{$_SESSION["ID"]}'" : $identifier;
// Connect to the database
$connection = connect("limited");
// Pass query, get result and fetch value out of it
$query = "SELECT * FROM `users` WHERE $identifier";
$result = mysqli_query($connection, $query);
if (mysqli_num_rows($result) > 0) {
$data = mysqli_fetch_assoc($result);
if(is_array($value))
{
foreach($value as $_value)
{
$return[$_value] = $data[$_value];
}
}
else
{
$return[$value] = $data[$value];
}
return $return;
}
mysqli_close($connection);
}
$x = retrieve(array("x1","x2","x3","x4","x5","x6"));
I have a function query:
function query() {
global $link;
$debug = false;
//get the sql query
$args = func_get_args();
$sql = array_shift($args);
//secure the input
for ($i=0;$i<count($args);$i++) {
$args[$i] = urldecode($args[$i]);
$args[$i] = mysqli_real_escape_string($link, $args[$i]);
}
//build the final query
$sql = vsprintf($sql, $args);
if ($debug) print $sql;
//execute and fetch the results
$result = mysqli_query($link, $sql);
if (mysqli_errno($link)==0 && $result) {
$rows = array();
if ($result!==true)
while ($d = mysqli_fetch_assoc($result)) {
array_push($rows,$d);
}
//return json
return array('result'=>$rows);
} else {
//error
return array('error'=>'Database error');
}
}
The function works just fine when I use it like this:
$g = "05%";
$result = query("SELECT * FROM table_name WHERE table_column LIKE '%s'", $g);
print json_encode($result);
However I am getting no result when $g is a value retrieved from a method. For example lets say I have a method getMonth() from a class Date that returns the current month of May as 05% when echoed. I try the code below and get nothing from the database:
$time = new Date();
//$g = "05%"; this would definitely get results from the db
$h = $time->getMonth();
echo $h; //this displays 05% on the screen
$result = query("SELECT * FROM table_name WHERE table_column LIKE '%s'", $h);
print json_encode($result);
I am pretty sure that I am making a simple mistake, but I can't seem to figure it out. How can I fix this? Any help would be greatly appreciated.
Do something that your method return only 05 part from 05%. and append % after that for example
$h = $time->getMonth();
$h = "$h%";
and then it should work
This question already has an answer here:
How to check fetched result set is empty or not?
(1 answer)
Closed 11 months ago.
What am I doing wrong here? I'm simply retrieving results from a table and then adding them to an array. Everything works as expected until I check for an empty result...
This gets the match, adds it to my array and echoes the result as expected:
$today = date('Y-m-d', strtotime('now'));
$sth = $db->prepare("SELECT id_email FROM db WHERE hardcopy = '1' AND hardcopy_date <= :today AND hardcopy_sent = '0' ORDER BY id_email ASC");
$sth->bindParam(':today', $today, PDO::PARAM_STR);
if(!$sth->execute()) {
$db = null;
exit();
}
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$this->id_email[] = $row['id_email'];
echo $row['id_email'];
}
$db = null;
return true;
When I try to check for an empty result, my code returns 'empty', but no longer yields the matching result:
$today = date('Y-m-d', strtotime('now'));
$sth = $db->prepare("SELECT id_email FROM db WHERE hardcopy = '1' AND hardcopy_date <= :today AND hardcopy_sent = '0' ORDER BY id_email ASC");
$sth->bindParam(':today',$today, PDO::PARAM_STR);
if(!$sth->execute()) {
$db = null;
exit();
}
if ($sth->fetchColumn()) {
echo 'not empty';
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$this->id_email[] = $row['id_email'];
echo $row['id_email'];
}
$db = null;
return true;
}
echo 'empty';
$db = null;
return false;
You're throwing away a result row when you do $sth->fetchColumn(). That's not how you check if there are any results. You do
if ($sth->rowCount() > 0) {
... got results ...
} else {
echo 'nothing';
}
Relevant documentation is here: PDOStatement::rowCount
If you have the option of using fetchAll() then, if there are no rows returned, it will just be an empty array.
count($sql->fetchAll(PDO::FETCH_ASSOC))
will return the number of rows returned.
You should not use rowCount for SELECT statements as it is not portable. I use the isset function to test if a select statement worked:
$today = date('Y-m-d', strtotime('now'));
$sth = $db->prepare("SELECT id_email FROM db WHERE hardcopy = '1' AND hardcopy_date <= :today AND hardcopy_sent = '0' ORDER BY id_email ASC");
// I would usually put this all in a try/catch block, but I kept it the same for continuity
if(!$sth->execute(array(':today'=>$today)))
{
$db = null;
exit();
}
$result = $sth->fetch(PDO::FETCH_OBJ)
if(!isset($result->id_email))
{
echo "empty";
}
else
{
echo "not empty, value is $result->id_email";
}
$db = null;
Of course this is only for a single result, as you might have when looping over a dataset.
I thought I would weigh in as I had to deal with this lately.
$sql = $dbh->prepare("SELECT * from member WHERE member_email = '$username' AND member_password = '$password'");
$sql->execute();
$fetch = $sql->fetch(PDO::FETCH_ASSOC);
// if not empty result
if (is_array($fetch)) {
$_SESSION["userMember"] = $fetch["username"];
$_SESSION["password"] = $fetch["password"];
echo 'yes this member is registered';
}else {
echo 'empty result!';
}
what I'm doing wrong here?
Almost everything.
$today = date('Y-m-d'); // no need for strtotime
$sth = $db->prepare("SELECT id_email FROM db WHERE hardcopy = '1' AND hardcopy_date <= :today AND hardcopy_sent = '0' ORDER BY id_email ASC");
$sth->bindParam(':today',$today); // no need for PDO::PARAM_STR
$sth->execute(); // no need for if
$this->id_email = $sth->fetchAll(PDO::FETCH_COLUMN); // no need for while
return count($this->id_email); // no need for the everything else
Effectively, you always have your fetched data (in this case in $this->id_email variable) to tell whether your query returned anything or not. Read more in my article on PDO.
One more approach to consider:
When I build an HTML table or other database-dependent content (usually via an AJAX call), I like to check if the SELECT query returned any data before working on any markup. If there is no data, I simply return "No data found..." or something to that effect. If there is data, then go forward, build the headers and loop through the content, etc. Even though I will likely limit my database to MySQL, I prefer to write portable code, so rowCount() is out. Instead, check the the column count. A query that returns no rows also returns no columns.
$stmt->execute();
$cols = $stmt->columnCount(); // no columns == no result set
if ($cols > 0) {
// non-repetitive markup code here
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
I only found one way that worked...
$quote = $pdomodel->executeQuery("SELECT * FROM MyTable");
//if (!is_array($quote)) { didn't work
//if (!isset($quote)) { didn't work
if (count($quote) == 0) { //yep the count worked.
echo 'Record does not exist.';
die;
}
Thanks to Marc B's help, here's what worked for me (note: Marc's rowCount() suggestion could work too, but I wasn't comfortable with the possibility of it not working on a different database or if something changed in mine... also, his select count(*) suggestion would work too, but, I figured because I'd end up getting the data if it existed anyway, so I went this way).
$today = date('Y-m-d', strtotime('now'));
$sth = $db->prepare("SELECT id_email FROM db WHERE hardcopy = '1' AND hardcopy_date <= :today AND hardcopy_sent = '0' ORDER BY id_email ASC");
$sth->bindParam(':today', $today, PDO::PARAM_STR);
if(!$sth->execute()) {
$db = null;
exit();
}
while ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
$this->id_email[] = $row['id_email'];
echo $row['id_email'];
}
$db = null;
if (count($this->id_email) > 0) {
echo 'not empty';
return true;
}
echo 'empty';
return false;