PHP7 produce error when array push is used on a string - php-7

How can I configure PHP 7 to produce an error when an item is pushed to a string, for example:
$items = '';
$items[] = 'test';
Is this possible?

In PHP 5.6 and 7.0, it is valid to convert a variable containing an empty string into an array like this. Therefore, you will need to provide your own validation to produce an exception.
function checkAndAssign($var, $val){
if (is_string($var)){
throw new ErrorException('Do not assign array item to a string');
}
return $val;
}
$items = '';
try{
$items[] = checkAndAssign($items, 'test');
}catch(Exception $e){
echo $e->getMessage();
return;
}
var_dump($items);
Results in:
Do not assign array item to a string
In PHP 7.1 this generates a Fatal Error. There is already a good answer to the question How do I catch a PHP Fatal Error if you want to attempt that.

Related

Podio - Embed Field - Empty string issue

Has anyone had any problems saving values to embed fields with the Podio PHP API?
I keep getting the following error, although I know my array has values:
Fatal error: Uncaught PodioBadRequestError: "Invalid value ""
(string): must be non empty string" See bold code below for field
returning empty.
I have also tried using the associative array, but get the error 'must use embed or url'. http://podio.github.io/podio-php/fields/#linkembed-field
$userItem->fields[$field->external_id] = new PodioEmbedItemField();
if (is_array($_POST[$embedName])) {
$embedArray = array();
$embedValues = $_POST[$embedName];
if (isset($embedValues) && !empty($embedValues)) {
for ($i = 0; $i < count($embedValues); $i++) {
$embedObject = PodioEmbed::create(array('url' => **$embedValues[$i]**));
array_push($embedArray, $embedObject);
}
$userItem->fields[$field->external_id]->values = new PodioCollection($embedArray);
}
}
OK problem is that PodioEmbed object cannot accept array iteration, you have to assign to a variable as string first and then pass into function.
$embedString = $embedValues[$i];
$embedObject = PodioEmbed::create(array('url' => $embedString));

Yii foreach error?

I have calling a function. get table number (result=0) results and updated same table value 0 to 1. i am using update query.i have run this function to return error :: Missing argument 2 for CDbCommand::update().
public function newdisplaycontent()
{
$count = Yii::app()->db->createCommand()
->select()
->from('scrolltable')
->where('result=:result', array(':result'=>0))
->queryAll();
$rs=array();
//print_r($count);
foreach($count as $item){
//process each item here
$rs=$item['ID'];
$user=Yii::app()->db->createCommand()
->update("scrolltable SET result = 1")
->where('ID=:id', array(':id'=>$rs));
}
return $rs;
}
thanks for your feature help..
The correct syntax of update() would be like below:
$user=Yii::app()->db->createCommand()
->update("scrolltable",array("result" => "1"))
->where('ID=:id', array(':id'=>$rs));
As official document:
update() Creates and executes an UPDATE SQL statement. The method will properly escape the column names and bind the values to be updated.
public integer update(string $table, array $columns, mixed $conditions='', array $params=array ( ))

bindValue and bindParam in mysqli and PDO ignore variable type

I'm having problems in understanding a part of the meaning of binding certain variable types in PDO and mysqli if the type given, in my case, seems to be meaningless. In the following code, the type bound (like i or s) gets ignored. The table row "wert_sortierung" in the database is INT(11). Regardingless if $val_int is really integer or not and if I bind it via i,s / PDO::PARAM_INT or _STR, the query always works, no break, no error or warning, that the types in the binding and database or variable itself don't fit.
<?
class PDOTest {
protected $pdo;
function __construct(){
$usr="usr";
$pwd="pwd";
$host="localhost";
$db="db";
$val_int="I'm a string";
$val_str="OP";
$querystring="SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = ? AND wert_CD = ?";
try {
$db_info = "mysql:host=$host;dbname=$db"; // usually provided via require_once and during construction
$this->pdo = new PDO($db_info, $usr, $pwd);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $this->pdo->prepare($querystring);
$stmt->bindValue(1,$val_int,PDO::PARAM_INT);
$stmt->bindValue(2,$val_str,PDO::PARAM_STR);
$stmt->execute();
$row_return = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->varprint($row_return);
$this->pdo = NULL;
}
catch (PDOException $ex) {
printf ('Es spricht:');
$this->printerror("Fehla! (" . $ex->getMessage() . ")");
$this->pdo = NULL;
exit();
}
printf("<br />-------<br />");
//Added for comparison
$mysqli = new mysqli($host, $usr, $pwd, $db);
$m_stmt = $mysqli->prepare($querystring);
$m_stmt->bind_param('is',$val_int, $val_str);
$m_stmt->execute();
$m_stmt->bind_result($row_return);
$m_stmt->fetch();
$this->varprint($row_return);
$m_stmt->close();
$mysqli->close();
}
private function printerror($txt) {
printf("<p><font color=\"#ff0000\">%s</font></p>\n",
htmlentities($txt));
}
private function varprint($var) {
echo "<br />";
echo "<pre>";
echo var_dump($var);
echo "</pre>";
}
}
new PDOTest();
?>
Please can anyone point out my error in reasoning.
It is actually Mysql's loose-typing that that deceived you.
As a matter of fact, regular Mysql queries can accept strings for the numberic values all right:
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = '1' AND wert_CD = '1';
while prepared statement just following this behavior.
However, a contrary situation is not that harmless. Addressing a string value with a number
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = 1;
will cause infinite number of warnings in case of wert_sortierung being of string type and some unexpected behavior, like matching for ALL the rows.
So, as a general advise I would suggest to always use 's' by default. The only drawback is PDO's emulated prepares and it can be easily worked around.
So, to answer your question explicitly - prepared statements just allow the same behavior as regular queries, adding nothing to it. Everything that possible with a regular query, is possible with prepared statement as well. And no, binding do not validate your data (however it should. Imn my class I test integer placeholders and throw an exception if no numeric value given)

Invalid parameter number: number of bound variables does not match number of tokens PDO insert

function mysql_insert($data_array){
$sql = "insert into `". $this->table_name. '`';
$array_keys = array_keys($data_array);
$array_keys_comma = implode(",\n", preg_replace('/^(.*?)$/', "`$1`", $array_keys));
for($a=0,$b=count($data_array); $a<$b; $a++){ $question_marks .="?,"; }
$array_values = array_values($data_array);
$array_values_comma = implode(",", $array_values);
$sql.= " ($array_keys_comma) ";
$sql.= " values(". substr($question_marks, 0,-1) .")";
$prepare = $this->connDB->prepare($sql);
$insert = $prepare->execute(array($array_values_comma));
}
I want to creat like this universal functions, $data_array-comes from $_POST
This function will work for all form. But i dont know what is my wrong :S
I don't know what is my wrong
That's quite easy to know: number of bound variables does not match number of tokens.
I want to creat like this universal functions, $data_array-comes from $_POST
Here you go: Insert/update helper function using PDO
$array_values_comma is a scalar after you implode() the array. So you always pass an array of one element to your execute() function. You should pass $array_values.
Here's how I'd write this function:
function mysql_insert($data_array){
$columns = array_keys($data_array);
$column_list_delimited = implode(",",
array_map(function ($name) { return "`$name`"; }, $columns));
$question_marks = implode(",", array_fill(1, count($data_array), "?"));
$sql = "insert into `{$this->table_name}` ($column_list_delimited)
values ($question_marks)";
// always check for these functions returning FALSE, which indicates an error
// or alternatively set the PDO attribute to use exceptions
$prepare = $this->connDB->prepare($sql);
if ($prepare === false) {
trigger_error(print_r($this->connDB->errorInfo(),true), E_USER_ERROR);
}
$insert = $prepare->execute(array_values($data_array));
if ($insert === false) {
trigger_error(print_r($prepare->errorInfo(),true), E_USER_ERROR);
}
}
A further improvement would be to do some validation of $this->table_name and the keys of $data_array so you know they match an existing table and its columns.
See my answer to escaping column name with PDO for an example of validating column names.

Accessing Associative Indexes Produced by PDO FETCH_ASSOC

I fully admit must have a faulty understanding of the construction of an associative array.
The following login script will populate $userdata with an associative array consisting of $username's hashed password and salt as queried from the SQL Server database (Azure SQL to be specific). However, the portions of the code that are working on creating a hash of the supplied password and comparing against the hashed password found in the DB fail with errors indicating that $userdata[password] and $userdata[salt] are undefined.
<?php
$username = $_POST['username'];
$password = $_POST['password'];
// Connect to SQL Server
include '../../phpconfig/connectstrings.php';
try
{
$conn = new PDO ( "sqlsrv:server = $serverstringname; Database = $databasestringname", "$usernamestringname", "$passwordstringname");
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION, );
}
catch ( PDOException $e )
{
print( "Error connecting to SQL Server." );
die(print_r($e));
}
catch(Exception $e)
{
die(var_dump($e));
}
//Query database for the hashed password and salt for the supplied username
if(!empty($_POST)) {
try
{
$sql_select = $conn->prepare("SELECT password, salt FROM logins WHERE username = '$username'");
$sql_select->execute();
}
catch(Exception $e)
{
die(var_dump($e));
}
//Fetch all of the remaining rows in the result set
$userdata = $sql_select->fetchAll(PDO::FETCH_ASSOC);
//check for a valid username
if(empty($userdata))
{
echo "User: $username was not found";
die;
}
//hash the queried salt and hash the supplied password
$hash = hash('sha256', $userdata['salt'] . hash('sha256', $password) );
//compare the hashed salted password supplied with that queried from database
if($hash = $userdata['password'])
{
echo "Welcome, $username!";
}
else
{
echo "Invalid password";
}
}
?>
While I don't doubt some of the code beyond fetching the array from $sql_select needs some debugging I can't get that far because $userdata appears to get all of the associative array data assigned to a single portion of the variable as indicated by the output of the following dumps:
var_dump($sql_select);
//output = object(PDOStatement)#2 (1) { ["queryString"]=> string(61) "SELECT password, salt FROM logins WHERE username = 'mrtactics'" }
list($a[0], $b[1]) = $userdata;
var_dump($a);
var_dump($b);
//output = array(1) { [0]=> array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" } } array(1) { [1]=> NULL }
var_dump($userdata["salt"]);
//output = NULL
var_dump($userdata['salt']);
//output = NULL
var_dump($userdata['password']);
//output = NULL
foreach ($userdata as $item => $value)
echo "$item: $value<br>";
//output = 0: Array
$password = $sql_select->fetchColumn(0);
$salt = $sql_select->fetchColumn(1);
var_dump($password);
var_dump($salt);
//output = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" bool(false)
The obvious workaround is to query a single value for the supplied username and pass each tot heir respective variables. However, this requires twice the necessary calls to the DB and I don't learn anything about how associative arrays are constructed and how I can get use the information stored within them.
I suspect I'm either fetching an object of the wrong construction for the method I am trying to retrieve from it or my syntax is just plain bad. I do intend to remain using PDO as opposed to sql_* commands.
EDIT: Let's make this more simple, then:
$userdatasql = $sql_select->fetchAll(PDO::FETCH_ASSOC);
$userdata['password']="f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a";
$userdata['salt']="6e0";
var_dump($userdata);
var_dump($userdatasql);
var_dump($userdata['password']);
var_dump($userdatasql['password']);
//Dump of $userdata = array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" }
//Dump of $userdatasql = array(1) { [0]=> array(2) { ["password"]=> string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a" ["salt"]=> string(3) "6e0" } }
Note the difference in the construction of these 2 arrays? I don't know exactly what it means which is why I'm here. If I were guessing it appears that the $userdatasql array contains an array within an array so calls must be indexed as such.
//Dump of $userdata['password'] = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a"
//Dump of $userdatasql['password'] = NULL
MORE INFO:
echo (count($userdata));
echo (count($userdatasql));
//output = 2
//output = 1
echo (count($userdata, 1));
echo (count($userdatasql, 1));
//output = 2
//output = 3
This tells me that the array created by PDO FETCH_ASSOC is of a different construction than an array manually created but containing the same 2 pieces of data and the same 2 indexes.
Armed with this knowledge I modified my dump to include the 0 index location and suddenly the expected data was being output:
var_dump($userdatasql['0']['password']);
var_dump($userdatasql['0']['salt']);
//password dump = string(64) "f24704c0ce72a618cf1738894ebdd6001f4d3329802ab83bd418df66cbc46b1a"
//salt dump = string(3) "6e0"
Does this mean that I must reference all PDO FETCH ASSOC arrays by index?
I should think not since no code examples I find show this.
So, then, why is my PDO FETCH ASSOC array malformed?
Well, I have the "answer" in the sense that I can format the syntax to retrieve the necessary information from the associative array. I do not understand the difference between a manually created associative array and one created by PDO FETCH ASSOC nor what the implications are going to be later on when my arrays are significantly more complex than the one posed here.
But, here's the "answer":
The information stored in the associative array created by PDO FETCH ASSOC must be referenced by the numerical index THEN the associative index despite being an associative array not of the numerical type (because that makes loads of sense, right?) By including the numerical index prior to the associative index the value was correctly obtained.
$var[0][index] //retrieves correctly
$var[index] //does not unless the array happened to be manually constructed
And the final, for real answer, deduced after hours of studying other relevant code examples:
My code is performing as it is because I am using ->fetchAll as opposed to ->fetch. When I use simply ->fetch I no longer have to reference both numerical and associative indexes and can simply reference the associative index as expected for an associative array.
The corrected code syntax follows:
<?php
$username = $_POST['username'];
$password = $_POST['password'];
// Connect to SQL Server
include '../../phpconfig/connectstrings.php';
try
{
$conn = new PDO ( "sqlsrv:server = $serverstringname; Database = $databasestringname", "$usernamestringname", "$passwordstringname");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch ( PDOException $e )
{
print( "Error connecting to SQL Server." );
die(print_r($e));
}
catch(Exception $e)
{
die(var_dump($e));
}
//Query database for the hashed password and the salt for the supplied username
if(!empty($_POST)) {
try
{
$sql_select = "SELECT password, salt FROM logins WHERE username = ?";
$stmt = $conn->prepare($sql_select);
$stmt->bindValue(1, $username);
$stmt->execute();
}
catch(Exception $e)
{
die(var_dump($e));
}
//Fetch the result set into an associative array
$userdata = $stmt->fetch(PDO::FETCH_ASSOC);
if(empty($userdata))
{
echo "User: $username was not found";
die;
}
//hash the queried salt with a hash of the supplied password
$hash = hash('sha256', $userdata['salt'].hash('sha256', $password));
//compare the hashed salted password supplied with that queried from database
if($hash == $userdata['password'])
{
echo "Welcome, $username!";
}
else
{
echo "Invalid password";
//does the user wish to register> -> header('Location: register.php');
die;
}
}
?>