Created class will not run query - php

I'm having issues running this code here:
<?php
include_once "global.php";
class Project{
//Variable declarations
public $name;
public $pm;
public $members;
public $details;
//Not sure if dates are necessary yet
//$startDate = $inStartDate;
//$endDate = $inEndDate;
//Define the constructor
function __construct($inName, $inPm, $inMembers, $inDetails){
$this->name = $inName;
$this->pm = $inPm;
$this->members = $inMembers;
$this->details = $inDetails;
//Not sure if dates are necessary yet
//$startDate = $inStartDate;
//$endDate = $inEndDate;
}
//Function to create the Project within the database
public function createProject(){
echo "starting";
//Initiate database connection, checking for errors
$con = dbConnect();
if ($con->connect_errno){
echo "Connect failed: %s\n". $mysqli->connect_error;
exit();
}
//Insert the project into the projects database using the information used to instantiate
if ($stmt = $con->prepare("INSERT INTO projects (name, details) VALUES (?,?)")){
echo "Not getting here.";
$stmt->bind_param('ss', $this->name, $this->details);
$stmt->execute();
if (strlen($stmt->error) > 0){
return "Error creating project. Contact system administrator.";
}
elseif(count($members) == 0) {
//ensure there are members to enter
$last_insert = mysqli_insert_id($con);
$con->query('INSERT INTO project_member (pid,uid,rid) VALUES ('.$last_insert.','.$this->pm.',1');
exit();
}
else{
//get last inserted ID
$last_insert = mysqli_insert_id($con);
echo $last_insert;
//loop through members and create sql array
$sql = array();
foreach ($members as $user){
$sql[]='("'.$last_insert.','.$user.',0")';
}
//Add members to join table with roles
$con->query('INSERT INTO project_member (pid,uid,rid) VALUES '.implode(',', $sql));
$con->query('INSERT INTO project_member (pid,uid,rid) VALUES ('.$last_insert.','.$this->pm.',1');
return true;
}
$stmt->close();
}
}
}
It will get to the mysqli code loop, but not initiate it. Trying to echo from it results in nothing being submitted, and the PHP error logs don't note anything going on. I don't see anything strange on the MySQL logs as well.
The $members variable is going to be an array composed of integers, which is why it loops at the bottom through the array.
I am not getting any connection errors, and echoing after trying to capture errors results in success.
dbConnect() is from the global.php file above, and returns a mysqli connection. This is the inside of the connection:
function dbConnect(){
$con = mysqli_connect($_HOST, $_DBUNAME, $_DBPASS,$_DBTABLE);
if ($con->connect_errno){
printf("Connect failed: %s\n", $mysqli->connect_error);
return false;
}
return $con;
}
I have used that elsewhere on my site, and in much of the same situation. Not sure what I am doing wrong here, but any advice would be greatly appreciated.
Edit: I did try again with all of the above suggestions, and still getting the weird issue with it not wanting to go past the if loop.
Edit2: Never mind, I am a moron.
Issue was that the 'details' row in my database didn't exist. Instead, in my infinite wisdom, I called it description and didn't update the code. Changing it fixed the issue.
Again, thank you all for a great first post on StackOverflow. I am going to be back, but I will get better!

This loop:
foreach ($members as $user){
$sql='("'.$last_insert.','.$user.',0")';
}
should be:
foreach ($members as $user){
$sql[]='("'.$last_insert.','.$user.',0")';
}
You're just overwriting the variable with a string, not appending to the array.
I'm surprise implode(',', $sql) on the next line isn't reporting an error.

You initialize $sql as an array, but then assign a string to it; you need to add items to an array differently:
$sql = array();
foreach ($members as $user){
$sql[] ='("'.$last_insert.','.$user.',0")';
}
Note the square brackets - that adds an extra item to the $sql array.
I'd also look at the two queries you're running at the end:
$con->query('INSERT INTO project_member (pid,uid,rid) VALUES '.implode(',', $sql));
$con->query('INSERT INTO project_member (pid,uid,rid) VALUES ('.$last_insert.','.$pm.',1');
You're adding two sets of values to the same table - $pm is never defined. You've got $pm as a class variable, but you don't set it as such. The syntax for that would be:
function __construct($inName, $inPm, $inMembers, $inDetails){
$this->name = $inName;
$this->pm = $inPm;
$this->members = $inMembers;
$this->details = $inDetails;
That means that the rest of the class functions can access those variables as $this->name, and so on.

The problem starts at your Project constructor:
The way you're initializing $name, $pm, $members, $details is keeping them local to the constructor. You want to initialize these variables using $this.
//Define the constructor
function __construct($inName, $inPm, $inMembers, $inDetails){
$this->name = $inName;
$this->pm = $inPm;
$this->members = $inMembers;
$this->details = $inDetails;
}
You can then safely get rid of all the global variables defined within functions, some of them including:
global $name;
global $details;
global $members;
Finally you need to access the member variables name, pm, members, details and any others using:
$this->name, $this->pm, and so on
Lastly as other answerers have already pointed out on the SQL string generation.
$sql = array();
foreach ($members as $user){
$sql[] = '("'.$last_insert.','.$user.',0")';
}

Related

php findall not displaying the content of my DB

first question here, because i'm stuck since this morning and i don't find a single way to fix my problem.
I'm trying to show every images listed in my DB (DB contains img name, img are stored in local files, each has been send in the same time via an input page).
The current code do not send any errors between thoses parts :
public function findall()
{
require_once ('Classes/ClasseDB.php');
$pdo = Database::connect();
$req = "SELECT IDphoto, nomImage, testCom FROM test";
$stmt = $pdo->query($req);
$CollectionPhotos = array();
while ($ligne = $stmt->fetch())
{
$LaPhoto = new ClasseTest($ligne["testCom"]);
array_push($CollectionPhotos, $LaPhoto);
}
return $CollectionPhotos;
}
public function get_nomImage()
{
return $this->nomImage;
}
And
Image List :
<?php
echo "test1 ";
require_once "Classes/ClasseTest.php";
$laPhoto = new ClasseTest;
$CollectionPhotos = $laPhoto -> findall();
$i = 0;
echo "test2 ";
while ($i < count($CollectionPhotos)){
// here is where it's broken ↓
echo $CollectionPhotos[$i]->get_nomImage(); //don't work :'(
//html <img __ > is removed in order to simplify
echo 'test3 '; //shows every items
$i++;
}
echo "test4 ";
?>
ClasseDB code here as asked :
<?php
class Database {
public static $conn = null;
public static function connect() {
if ( null == self::$conn ) {
try {
self::$conn = new PDO('mysql:host=localhost;dbname=myDB', 'root', '');
self::$conn->query("SET NAMES 'utf8'");
self::$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
die($e->getMessage());
}
}
return self::$conn;
}
}
?>
Each tests are shown, and 'test3' appears 10 times, so i know my loop repeats enough times.
Nb : this is like what we did in class...
So what is wronnnng, is that a newbie mistake, a misspelling or a bug (my pc has done everything to me so that's also possible) ?
In your SQL query, you select three columns:
SELECT IDphoto, nomImage, testCom FROM test
However, only one of these is actually referenced in your PHP code:
$LaPhoto = new ClasseTest($ligne["testCom"]);
You haven't shown the constructor of ClasseTest, so it's not clear where testCom is stored (if anywhere), but from its name, I suspect it is not in the nomImage property, which is what you later try to retrieve:
public function get_nomImage()
{
return $this->nomImage;
}
That property is presumably supposed to come from the nomImage column in the database, which you're not storing anywhere.
You can help yourself a lot by naming things more carefully and thinking about responsibilities. If you want an object representing a photo, the logical name for it would be Photo, and you would pass all the columns you've selected to its constructor:
$LaPhoto = new Photo($ligne["IDphoto"], $ligne["nomImage"], $ligne["testCom"]);
Your findAll method doesn't belong to a single photo, so you can either put it on a different class, like ChercheurPhoto:
$leChercheurPhoto = new ChercheurPhoto;
$CollectionPhotos = $leChercheurPhoto->findall();
Or, you can use a static method, which is a method on the class, not a particular instance of the class:
$CollectionPhotos = Photo::findall();

Mysqli last insert id not work

I am trying to get last query insert id.but my code always return zero.
My Code
private function Cnn()
{
return mysqli_connect('localhost','root','root','db');
}
protected function MyCommandInsertId($sql)
{
if(mysqli_query($this->Cnn(),$sql))
{
return mysqli_insert_id($this->Cnn());
}
$this->err = mysqli_error($this->Cnn());
return false;
}
public function Insert()
{
$sql = "insert general_info(name,email,password)
values('".$this->ms($this->name)."','".$this->ms($this->email)."','".md5($this->password)."')";
//print''.$sql.'';
$last_insert_id=$this->MyCommandInsertId($sql);
}
here return mysqli_insert_id($this->Cnn()); always return zero
Please check the definition of mysqli_insert_id:-
The mysqli_insert_id() function returns the id (generated with AUTO_INCREMENT) used in the last query.
It means either column in your table that have AUTO_INCREMENT value is not exist.
Or
No insertion of data happen programmatically on your table in the curren program flow. Since no insert query is fired in your code, it returned Zero.
Note:- Just do an insert query first in your code and then check what is the output given by mysqli_insert_id. Then you can understand easily what i am trying to say.Thanks
A working example of my local is here:-
<?php
error_reporting(E_ALL);
ini_set('display_errors',1);
function Cnn()
{
$conn = mysqli_connect('localhost','root','','stack');
return $conn;
}
function MyCommandInsertId($sql)
{
$conn = Cnn();
if(mysqli_query($conn,$sql))
{
$lastid = mysqli_insert_id($conn);
return $lastid;
}else{
$err = mysqli_error($conn);
return $err;
}
}
function Insert()
{
$sql = "INSERT INTO bom(bom_description,product_id,finish_product,bom_quantity,UOM) values('Table cleaner','','','','')";
$st_insert_id = MyCommandInsertId($sql);
echo $st_insert_id;
}
Insert();
?>
Output:- http://prntscr.com/9u2iyv (inserted id) and http://prntscr.com/9u2j6i(table view after insertion)
According to
http://php.net/manual/en/mysqli.insert-id.php
There 2 possible problems
no previous query on the connection
the query did not update an AUTO_INCREMENT value
solutions:
Check there is an new record inserted in your table
Check that whether your field is AUTO_INCREMENT or not.
By CBroe, you are make a new connect.
So, it considers you did not insert the new record.
rewrite the function Cnn() and change it into a private variable.
In my case, my sqli was declared outside the current function scope
$conn = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
What I needed to do was to add global in front of my $conn
function want() {
///...... query stuff
global $conn;
$conn->insert_id; // Now works
}

The lifecycle of an object in PHP

I have two PHP scripts that I included below. Both of them attempt to do the same thing, but one works and one does not. I'm looking for someone to explain what PHP is doing under the covers. I'm new to PHP and I suspect that my Java experience is poisoning my thought process when I work in PHP.
What I'm attempting to do is functionally very simple -- Insert a question into a mySQL database table, retrieve the primary key of the inserted row, and then insert five answers into another table with a foreign key relationship to the question.
My original logic looked like this:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$query = new Query;
$query->createTransaction();
$query->executeCreateUpdateDelete("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$question_pid = $query->getLastInsertedId();
$query->commitTransaction(); // Need to figure out how to do dirty reads so I can remove this.
echo $question_pid."<br>";
$result = $query->executeRead("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
echo count($result)."<br>";
//if (count($result) === 1) {
$query->createTransaction(); // Need to figure out how to do dirty reads so I can remove this.
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$query->executeCreateUpdateDelete("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
if ($answer['isCorrect'] === 1) {
$correctAnswers = $correctAnaswers + 1;
if ($correctAnswers > 1){
echo "Failed to insert answers";
$query->rollBackTransaction();
break;
}
}
}
echo "Success";
$query->commitTransaction();
/* } else {
echo "Failed to insert question";
$query->rollBackTransaction();
} */
}
?>
Query.php:
<?php
session_start();
class Query
{
private $host="<censored>";
private $username="<censored>";
private $password="<censored>";
private $db_name="<censored>";
private $pdo;
private $pdo_statement;
private $pdo_exception;
public function executeCreateUpdateDelete($pQuery)
{
$this->pdo_statement = $this->pdo->prepare($pQuery);
return $this->pdo_statement->execute();
}
public function executeRead($pQuery)
{
try
{
$dbh = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$result = $dbh->query($pQuery);
$dbh = null;
return $result->fetchAll();
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
$this->pdo->beginTransaction();
}
public function commitTransaction()
{
$this->pdo->commit();
}
public function rollBackTransaction()
{
$this->pdo->rollBack();
}
public function getLastInsertedId()
{
$this->pdo->lastInsertId();
}
}
?>
When I rewrote my logic to not use a separate query class, I was able to do what I wanted to do. The only thing I've been able to find online about the life cycle of a PHP object is that it begins at the start of a script and ends at the end of a script. Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends? Moving the logic out of that class and into the script caused my logic to work. This is what it looks like now:
ManageQuestions.php:
<?php
session_start();
include('query.php');
echo "Begin <br>";
if (isset($_POST['submit'])) {
echo "manageQuestion <br>";
$host="<censored>";
$username="<censored>";
$password="<censored>";
$db_name="<censored>";
$pdo = new PDO("mysql:host=$host;dbname=$db_name", $username, $password);
$stmt = $pdo->prepare("INSERT INTO question (question) VALUES ('".$_POST['question']."'); ");
$stmt->execute();
$question_pid = $pdo->lastInsertId();
echo $question_pid."<br>";
$stmt = $pdo->query("SELECT question_pid FROM question where question_pid = '".$question_pid."';");
$result = $stmt->fetchAll();
echo count($result)."<br>";
foreach($_POST['answer'] as $answer) {
$correctAnswers = 0;
$stmt = $pdo->prepare("INSERT INTO answer (question_fid, answer, isCorrect) VALUES ('".$question_pid."','".$answer['answer']."','".$answer['isCorrect']."')");
$stmt->execute();
}
echo "Success";
}
?>
Even though this fixed my issue, I don't understand why. If someone could explain that, I would be extremely grateful.
Cheers!
Does that imply that my query object is instantiated every time I call one of its methods and garbage collected when that particular method ends?
No. It's per request, not per method call. So the query object is instantiated every time the script is called and it gets unset (and not necessarily garbage collected) when the script ends.
However you could better manage the resource of the PDO object inside your Query class because you create a new instance (which would mean that it connects again to the database server which is not that cheap). So some lazy loading does not seem bad:
class Query
{
...
/** #var PDO */
private $pdo;
...
private function getPdo() {
if (!$this->pdo) {
$this->pdo = new PDO("mysql:host=$this->host;dbname=$this->db_name", $this->username, $this->password);
}
return $this->pdo;
}
public function executeRead($pQuery)
{
try {
$dbh = $this->getPdo();
$result = $dbh->query($pQuery);
return $result->fetchAll();
} catch (PDOException $e) {
echo $e->getMessage();
}
}
public function createTransaction()
{
$this->getPdo()->beginTransaction();
}
...

Php database models

<?php
class ann {
public function __construct($context, $orgs_id, $created_at) {
$this->context = $context;
$this->orgs_id = $orgs_id;
$this->created_at = $created_at;
}
function create(){
$createann = mysql_query("INSERT INTO anns(context,
orgs_id, created_at)
VALUES('$this->context',
$this->orgs_id, '$this->created_at'");
if($createann) echo "Duyuru Başarıyla Eklendi"; else echo "Duyuru
Eklenemedi";
}
function read($id){
$readann = mysql_query("SELECT * FROM anns WHERE id = $id");
$context = mysql_result($readann,0, "context");
$orgs_id = mysql_result($readann,0, "orgs_id");
$created_at = mysql_result($readann,0,
"created_at");
$ann = new ann($context, $orgs_id, $created_at);
return $ann;
}
function update($id, $context){
$updateann = mysql_query("UPDATE anns SET context =
'$context' WHERE id = $id");
if($updateann) echo "Update success"; else echo
"Update failed";
}
function delete($id){
$deleteann = mysql_query("DELETE FROM anns WHERE id
= $id");
if($deleteann) echo "Delete success"; else echo "Delete not success";
}
//crud fonksiyonlari burda bitiyor
}
?>
There is something wrong with our logic here but we are very new to php. We tried to create rails like models, but it think something with our class-object notation is wrong. So the code did not work. We cannot even create any object with it.
Thank you guys
context, orgs_id and created_at must be should be first declared either as public, private or protected before you use them.
In your create method, you don't filter user input. This may cause to your application SQL injection, you have to you always filter user input. Use either mysql_real_escape_string or prepared statment by PDO.
You may check this tutorial.
two things (which maybe only apply to your codesample here):
In your sample, you dont close your
Class, because the last "}" is
commented out.
You never opened a connection to your database, so the query would fail.
a few observations:
declaring the attributes in the constructor is possible, but it's not elegant. I'd rather do:
class ann {
private $context;
private $orgs_id;
the "->" operator won't work inside a string. You'll need to concatenate the query:
"INSERT INTO anns(context,orgs_id, created_at) VALUES('".$this->context."',".$this->orgs_id".", '".$this->created_at."'"
but be careful on sql injection
The rest should be fine! Good Luck.

PHP/MySQL isolating database access in a class - how to handle multiple row result set in an OOP manner

PHP/MySQLisolating database access in class - how to handle multiple row Selects
Here’s a coding question.
I isolated all DB access functions in a class
<?php
class DB {
var $conn;
function DBClass () {
#$this-> conn = mysqli_connect (DB_SERVER, DB_USER, DB_PASS, DB_NAME);
}
function validateUser ($aUserid, $aPassword) {
… validation code – sql injection code etc..
$sql = "Select userid, name, level From users where userid = '$aUserid' and password = '$aPassword'";
$result = mysqli_query ( $this->conn, $sql );
if (!$result || (mysqli_num_rows ($result) < 1)) {
return false;
}
$dbarray = mysqli_fetch_assoc ($result); // get a row
return $dbarray;
}
function getProduct ($aProductid) {
return $dbarray;
}
function getProductList () {
// <----------- this would be the problem function
}
}
$DB = new DBClass();
?>
My calling routine:
<?php
$dbarray = $DB->validateUser ($_POST['userid'], $_POST['password']);
?>
No problem it works fine. I run into a problem with a result set of more than one row. Now I have to get back to the class object for each row. It’s no problem if I include the MySQL code in the calling routine, but I’d like to keep it isolated in my class and I’m not sure how to code it.
Any thoughts? Any examples?
If you use PHP 5.3.0 and mysqlnd, you can use the new function mysqli_fetch_all(). This returns an array of associative arrays.
If you use an earlier version of PHP, you could switch to using PDO, and use the function PDOStatement::fetchAll().
You ask in a comment what about a very large result set. It's true that an unbounded result set could cause the array to exceed your PHP memory limit and that would cause a fatal error and halt the script. But is this really a problem? How many products do you have? You could use LIMIT to make sure the query isn't unbounded.
Re the other part of your questions regarding going back to a class, I'd suggest making an Iterator class:
class DB implements IteratorAggregate
{
protected $_data = array();
public function getProductList() {
// fetch all results from SQL query, stuff them into $this->_data
return $this->getIterator();
}
public function getIterator() {
return new ArrayIterator($this->_data);
}
}
Now you can use the class in a foreach loop:
$db = new DB();
foreach ($db->getProductList() as $product) {
// do something with each product
}
The IteratorAggregate interface means you can even do this:
$db = new DB();
$db->getProductList();
// ...other steps...
foreach ($db as $product) {
// do something with each product
}
Of course you could only store one result set at a time with this method. If you used your DB class for any other queries in the meantime, it would complicate things. For this reason, most people don't try to write a single class to encapsulate all database operations. They write individual classes for each type of Domain Model they need to work with, decoupled from the database connection.
you could save the result in an array and return it:
function getProductList () {
$sql = "SELECT ...";
$result = mysqli_query ( $this->conn, $sql );
$myProducts = array();
while ($row = mysqli_fetch_assoc($result))
$myProducts[] = $row; // or array_push($myProducts, $row)
}
return $myProducts
}
As a result you'll have an array of arrays and each element of it will contain one row of the result.
You have a SQL injection right in your login page.
What happens if someone inputs that as password:
xxx' OR 'yyy' <> 'x

Categories