I'm working with database with a lot of columns with 'enum' and 'set' type. My point is to get values of column in Phalcon controller. I found some snippets, but nothing in Phalcon and when I tried to execute them it seems that Phalcon have some problems.
public function getEnumValues(){
$sql = "SHOW COLUMNS FROM profiles LIKE 'eyes_color'";
$query = new \Phalcon\Mvc\Model\Query($sql, $this->getDI());
$result = $query->execute();
return $result;
}
Returns:
Syntax error, unexpected token IDENTIFIER(SHOW), near to ' COLUMNS FROM profiles LIKE 'eyes_color'', when parsing: SHOW COLUMNS FROM profiles LIKE 'eyes_color'
Approach 2:
public function getEnumValues(){
$sql = "SELECT COLUMN_TYPE FROM COLUMNS WHERE TABLE_NAME = 'profiles' AND COLUMN_NAME = 'hair_color'";
$query = new \Phalcon\Mvc\Model\Query($sql, $this->getDI());
$result = $query->execute();
return $result;
}
Returns:
Model 'COLUMNS' could not be loaded
I would be grateful for any help.
This is working version for your needs:
$config = $this->getDI()->get('config');
$pdo = new \Phalcon\Db\Adapter\Pdo\Mysql([
"host" => $config->database->host,
"username" => $config->database->username,
"password" => $config->database->password,
"dbname" => $config->database->dbname,
]);
$sql = "
SELECT TRIM(TRAILING ')' FROM SUBSTRING(COLUMN_TYPE,6)) AS enum_list
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='my_db_name'
AND TABLE_NAME='my_table_name'
AND COLUMN_NAME='my_column_name'
";
$result = $pdo->query($sql)->fetch();
$enumArray = array();
if (!empty($result['enum_list'])) {
$enumArray = explode(',', $result['enum_list']);
foreach ($enumArray as &$value) {
$value = trim($value, "'");
}
}
echo "<pre>"; var_dump($enumArray); die;
Could you get what you want from the columnMap function in the model?
$model = new Profile();
$columns = $model->columnMap();
This will return an array of all columns. Possible create another similar function to just return the columns you want? Perhaps what you're trying to achieve is more involved.
BTW I got the same error using the modelManager.
Related
Iam trying to make a OOP based forum in PHP and currently im stuck at making the Database class. Specifically Iam stuck at making a "general purpose" insert class function for the Datatable class (using PDO btw).
class DB
{
private $dbconn;
public function __construct(){
}
protected function connect($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass=''){
try{
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
catch(PDOException $e){
echo 'Connection failed: '.$e->getMessage()."<br />";
}
}
protected function disconnect(){
$this->dbconn = null;
}
public function insert($dbname, ){
$this->connect($dbname);
try{
# prepare
$sql = "INSERT INTO pdodemotable (firstname, lastname, age, reg_date)
VALUES (?, ?, ?, now())";
$stmt = $dbconn->prepare($sql);
# the data we want to insert
$data = array($firstname, $lastname, $age);
# execute width array-parameter
$stmt->execute($data);
echo "New record created successfully";
}
catch(PDOException $e){
echo $sql . "<br>" . $e->getMessage();
}
}
}
The insert function is as you see unfinished. I cant figure out how to get the insert function to adapt to ANY amount of arguments, ANY amount of database columns and ANY table. The code thats in the function right now is taken from one of my other projects where I used procedural programming. Its by first time using OOP with Databases.
Im a newbie to both OOP and PDO. There must be some sort of method or function that could help me that Im missing. The only solution I see right now is to use a ridicoulus amount of string handling and if statement... it cant be the best solution... there must be a easier way...
First notice - you don't need the $dbname parameter for insert method, instead it should be a constructor parameter:
class DB {
private $dbconn;
public function __construct($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass='') {
// also don't catch the error here, let it propagate, you will clearly see
// what happend from the original exception message
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
...
}
As for the insert method - first try to imagine how it will be used.
For example, it can be like this:
$db = new DB('mydb');
$db->insert('mytable', array('firstname'=>'Pete', 'lastname'=>'Smith'));
Then you can pass the table name and data (keys/values) into the method:
public function insert($table, $data) {
// again, no need to try / catch here, let the exceptions
// do their job
// handle errors only in the case you are going to fix them
// and not just to ingnore them and 'echo', this can lead to much worse problems
// see the explanation below regarding the `backtick` method
$table = $this->backtick($table);
$fields = array();
$placeholders = array();
$values = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key);
// you can also process some special values like 'now()' here
$placeholders[] = '?';
}
$fields = implode($fields, ','); // firstname, lastname
$placeholders = implode($placeholders, ','); // ?, ?
$sql = "INSERT INTO $table ($fields) values ($placeholders)";
$stmt = $this->dbconn->prepare($sql);
$stmt->execute(array_values($data));
}
public function update($table, $id, $data) {
$table = $this->backtick($table);
$fields = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key) . " = ?";
}
$fields = implode($fields, ','); // firstname=?, lastname=?
$sql = "UPDATE $table SET $fields where id=?";
$stmt = $this->dbconn->prepare($sql);
$data['id'] = $id;
$stmt->execute(array_values($data));
if ($stmt->execute(array_values($data)) === false) {
print 'Error: ' . json_encode($stmt->errorInfo()). PHP_EOL;
}
while ($row = $stmt->fetchAll()) {
print json_encode($row) . PHP_EOL;
}
}
private function backtick($key) {
return "`".str_replace("`","``",$key)."`";
}
Another alternative is to create the separate object which will represent one table row (the ActiveRecord pattern).
The code which uses such object could look like this:
$person = new Person($db);
$person->firstName = 'Pete';
$person->lastName = 'Smith';
$person->save(); // insert or update the table row
Update on possible SQL injection vulnerability
I also added the update and backtick methods to illustrate the possible SQL injection.
Without the backtick, it is possible that update will be called with something like this:
$db->updateUnsafe('users', 2, array(
"name=(SELECT'bad guy')WHERE`id`=1#"=>'',
'name'=>'user2', 'password'=>'text'));
Which will lead to the SQL statement like this:
UPDATE users SET name=(SELECT'bad guy')WHERE`id`=1# = ?,name = ?,password = ? where id=?
So instead of updating the data for user with id 2, we it will change the name for the user with id 1.
Due to backtick method, the statement above will fail with Unknown column 'name=(SELECT'bad guy')WHEREid=2#' in 'field list'.
Here is the full code of my test.
Anyway, this probably will not protect you from any possible SQL injection, so the it is much better not to use the user input for known parameters like table name and field names.
Instead of doing something like $db->insert('mytable', $_POST), do $db->insert('mytable', array('first'=>$_POST['first'])).
Try to pass the arguments has an array, then, inside the method insert, do a foreach.
Something like:
$data['first_name'] = 'your name';
...
$data['twentieth_name'] = 'twentieth name';
foreach( $data as $key => $value )
$final_array[':'.$key] = $value;
$stmt->execute( $final_array );
I am using adapter in zend framework 2. My code is for mysql update query which is not working, can any one suggest me. Array result is ok but its not display in query. Just shows update tablename set.
I have tried all suggestions of SO and also from Google, but I am failed to solve that problem.
Code is here:
public function updatebhkdetail($bhkupdate)
{
$WHERE = 'project_id='.$bhkupdate['project_id'];
$sql = new Sql($this->adapter);
$update1bhk = $sql->update('tablename', array($bhkupdate), $WHERE);
$statementUpdate = $sql->getSqlStringForSqlObject($update1bhk);
$sectorName = $this->adapter->query($statementUpdate,
\Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
}
I'm not to familiar with getSqlStringForSqlObject. But this should work:
$sql = new Sql( $this->adapter );
$update = $sql->update();
$update->table( <yourTableName> );
$update->set( $keyValues );
$update->where( array( 'project_id' => $bhkupdate['project_id'] ) );
$statement = $sql->prepareStatementForSqlObject( $update );
$results = $statement->execute();
I'm trying to write a PHP-script that will fetch multiple rows from MySQL and return them as a JSONObject, the code works if I try to only fetch 1 row but if I try to get more than one at a time the return string is empty.
$i = mysql_query("select * from database where id = '$v1'", $con);
$temp = 2;
while($row = mysql_fetch_assoc($i)) {
$r[$temp] = $row;
//$temp = $temp +1;
}
If I write the code like this it returns what I expect it to, but if I remove the // from the second row in the while loop it will return nothing. Can anyone explain why this is and what I should do to solve it?
You are using an obsolete mysql_* library.
You are SQL injection prone.
Your code is silly and makes no sense.
If you really wan to stick to it, why simply not do:
while($row = mysql_fetch_assoc($i)) {
$r[] = $row;
}
echo json_encode($r);
And finally, an example using PDO:
$database = 'your_database';
$user = 'your_db_user';
$pass = 'your_db_pass';
$pdo = new \PDO('mysql:host=localhost;dbname='. $database, $user, $pass);
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
try
{
$stmt = $pdo->prepare("SELECT * FROM your_table WHERE id = :id");
$stmt->bindValue(':id', $id);
$stmt->execute();
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
catch(\PDOException $e)
{
$results = ['error' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine());
}
echo json_encode($results);
You don't need the $temp variable. You can add an element to an array with:
$r[] = $row;
Here is my model code below,
public function insertme()
{
$sel = new Sql($this->adapter);
$s = $sel->insert('users');
$data = array(
'fname'=>'fisdsds',
'lname'=>'sdsdsdme',
'email'=>'sdsdsds',
'pword'=>'dsdsds'
);
$s->values($data);
$statement = $sel->prepareStatementForSqlObject($s);
$comments = $statement->execute();
$resultset = new ResultSet();
$resultset->initialize($comments);
$result = $resultset->toArray();
//print_R($result);
return $result;
}
it is inserting data into database table users but iam also getting an error SQLSTATE[HY000]: General error what could be the problem?
There's no need to try and make a ResultSet from an insert, it's not going to give you back any resultset data.
public function insertme()
{
$sel = new Sql($this->adapter);
$s = $sel->insert('users');
$data = array(
'fname'=>'fisdsds',
'lname'=>'sdsdsdme',
'email'=>'sdsdsds',
'pword'=>'dsdsds'
);
$s->values($data);
$statement = $sel->prepareStatementForSqlObject($s);
$result= $statement->execute();
//print_R($result);
return $result;
}
I am selecting data from a database. The database field names are exactly the same as the class variable names. Is there a way to store this data into the class variables without specifying each one individually?
//gets info about a specified file.
//chosen based on a supplied $fileId
function getFileInfo($fileId)
{
//select info from database
$sql = "SELECT id, companyId, url, name, contentType, fileSize, saved, retrieved
FROM files
WHERE id = $fileId";
$results = $this->mysqli->query($sql);
$results = $results->fetch_object();
//store info into class variables
$this->id = $results->id;
$this->companyId = $results->companyId;
$this->url = $results->url;
$this->name = $results->name;
$this->contentType = $results->contentType;
$this->fileSize = $results->fileSize;
$this->saved = $results->saved;
$this->retrieved = $results->retrieved;
}
A quick and dirty way would ba a loop:
foreach($result as $var => $value) {
$this->$var = $value;
}
I'd propose this approach:
$nameMap = array(
'id',
'companyId',
'url',
'name',
'contentType',
'fileSize',
'saved',
'retrieved',
);
foreach( $nameMap as $attributeName ) {
$this->$attributeName = $results->$attributeName ;
}
While one could write
foreach($result as $var => $value) {
...
}
the outcome fully depends on backing table's structure. If you add further attributes to the table, your code might break.
Using $nameMap, the application still works.
Just use foreach structure:
foreach ($result as $column => $value) {
$this->$column = $value;
}
Not nice but will work.
Humm. Well, PDO has native functions for that, if you're not married to mysqli for some reason:
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
$sth = $dbh->prepare("SELECT name, colour FROM fruit");
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
print $result->NAME;
The biggest disadvantage I've found is that PDO doesn't support SSL connections between the PHP machine and the MySQL machine.