Format MySQL code inside PHP string - php

Is there any program IDE or not that can format MySQL code inside PHP string e.g.
I use PHPStorm IDE and it cannot do it.
It does that for PHP and MYSQL but not for MYSQL inside php string. I am ready to use new IDE because now i have to manually format hundreds of database requests that are one line and not readable. Only criteria for my choice is that ide can do that automatically.
<?php
...
$request1 = "select * from tbl_admin where admin_id= {$_SESSION['admin_id']} and active= 1 order By admin_id Asc";
...
?>
should become
<?php
...
$request1 = "SELECT *
FROM tbl_admin
WHERE admin_id = {$_SESSION['admin_id']}
AND active = 1
ORDER BY admin_id ASC";
...
?>

The best way to do this in my opinion is to use Regular Expressions or SED/AWK to format everything, it gives us the bonus of replacement maps on the fly. The chance that you might have code errors though is high, so it's kind of tough.
let me work on it a bit and I can see if I can come up with a good
solution. Is it guaranteed that you are encapsulating all SQL in
double quotes?
EDIT
Try this
cd {{directory}} && find . -type f -print0 |
xargs -0 perl -i.bak -pe 's/select/SELECT/g ; s/from/\n\tFROM/g ; s/where/\n\t\tWHERE/g ; s/and/\n\t\tAND/g ; s/order by/\n\t\tORDER BY/g ; s/asc/ASC/g ; s/desc/DESC/g ;'
Here's an example
$ printf '"select * from whatever where this = that and active = 1 order by something asc";\n' |
> perl -pe 's/select/SELECT/g ; s/from/\n\tFROM/g ; s/where/\n\t\tWHERE/g ; s/and/\n\t\tAND/g ; s/order by/\n\t\tORDER BY/g ; s/asc/ASC/g ; s/desc/DESC/g ;'
"SELECT *
FROM whatever
WHERE this = that
AND active = 1
ORDER BY something ASC";
Is it pretty? no, not at all, does it work.... Yeup.
I'll try creating a filter file and maybe a little bash program or something as i get time to run this hot mess.
EDIT
Here's some revised code, looks prettier (sorta)
printf '$request1 = "select * from whatever where this = that and active = 1 order by something asc";\n' |
perl -pe 's/select/SELECT/gi ; s/from/\n FROM/gi ; s/where/\n WHERE/gi ; s/and/\n AND/gi ; s/order by/\n ORDER BY/gi ; s/asc/ASC/gi ; s/desc/DESC/gi ;' |
awk 'NR == 1 {pad = length($0)/2; print} NR > 1 {gsub(/\r/,""); printf "%*s%s\n", pad, " ", $0}'
__OUTPUTS__
$request1 = "SELECT *
FROM whatever
WHERE this = that
AND active = 1
ORDER BY something ASC";

As fas as I know PhpStorm can do it, if you use the heredoc syntax
$request1 = <<<SQL
SELECT *
FROM tbl_admin
WHERE admin_id = {$_SESSION['admin_id']}
AND active = 1
ORDER BY admin_id ASC
SQL;

The answer is NO.
As an alternative solution, I can suggest copying the text (ALL THE PHP CODE in the *.php file) into the query editor of Heidisql, clicking Re-Format and copying back to NetBeans and pressing Alt+Shift+F. This will format sql and format php code after, preserving sql formatting. SO instead of a plug in, you're copying, formatting a whole file, copying back and formatting again.
Instead of HeidiSQL, you can use this tool, which is focused on formatting if you are comfortable with web tools like these.
If you want more automation, you can use regular expression support of netbeans to format with backslash n = \n for new line befre each "insert, update delete, select, where and values" terms
running this 6 times will replace all " insert" <- blank plus insert, in your projects with new lines. you can write a regular expression for searching all, "blank plus reserved word", combinations and replace them with new lines.
You can also use it like search for " insert" and repalce with "\n\t insert", which would create a new line an a tab

Considering the question: Is there an IDE that will automatically format sql queries, I must concur with ugurcode. The answer is simple: there isn't any. And with good reason.
Basically an SQL query is nothing but a string in any IDE. Since strings can contain intentional whitespaces and tabs, it would be very bad if an IDE would reformat string content.
The only option that would work for any IDE would be to detect INSERT, UPDATE, DELETE at the start of a string and then format the rest of the string.. ofcourse it would also try to do the same with a string saying "insert quote here..", which once again would be a bad thing.
Since i don't want to leave you with just nothing i will give you advice on a good IDE to choose which does in fact do proper code formatting, code completion, good indentation, plugins etc.. and basically is the best IDE for php development (atleast its the best i've found in my years of professional php development).
Netbeans would be your IDE of choice. It's faster then i.e. Eclipse/PHP, more stable then i.e. codelobster etc.

Log, profile your SQL statements.
Use an external service such as this one - SQLFormat API - in order to format your SQL statements
You can also run it on your machine dowloading the Python sources.

Since your problem is to format an existing body of code, you don't need an IDE. You need a script to batch-process all your files once, and then you can forget about it. This is what the script needs to do:
Correctly parse PHP strings, including strings with all sorts of embedded or escaped quotes. This should be bullet-proof, and should only care about PHP syntax.
Check each PHP string with an algorithm that detects SQL commands. This can be made as smart as you need it to be (no need to blindly accept every string containing the word "insert", for example).
Feed the identified strings through an SQL pretty-printer.
Edit the input file, substituting the formatted string for the original one.
Ideally, parts 1 and 3 should be handled by off-the-shelf modules. The rest should be easy to put together yourself, right?
Update: Explaining this made it sound so simple, I decided to do it myself. Here's a quick solution. It's in python, but if you were willing to switch IDEs you can deal with installing python, right?
Drag-and-drop any number of php files onto the script, or call it from the commandline, and it will filter the SQL bits through the SQLFormat API that #Parahat suggested. It edits the files in place, so keep a copy!
"""Format sql strings embedded in php code, editing source IN PLACE"""
import sys, re, urllib, urllib2
def processfile(fname):
with open(fname) as fp:
text = fp.read()
with open(fname, "w") as out:
for token in chunk(text):
if is_sql_string(token):
token = token[0] + sqlformat(token[1:-1]) + token[0]
out.write(token)
def sqlformat(query):
sqlapi = 'http://sqlformat.appspot.com/format/?keyword_case=upper&reindent=1&n_indents=4&'
return urllib2.urlopen(sqlapi+urllib.urlencode({'data':query})).read()
php_mode = False # global, so that is_sql_string() can examine it
def chunk(src):
"""Chunk the php file into interesting units"""
global php_mode
while src:
if not php_mode: # Read up to the next php group, if any
m = re.match(r".*?<\?php", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
php_mode = True
else: # No more php groups: EOF
yield src
return
else: # Reading php code
# PHP ends without another string?
m = re.match(r"[^'\"]*?\?>", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
php_mode = False
continue
# at non-string material?
m = re.match(r"[^'\"]+", src)
if m:
tok, src = _usematch(m, src)
yield tok
continue
# Parse a string: Smallest quote-delimited sequence,
# where closing quote is not preceded by backslash
m = re.match(r'".*?(?<!\\)"|' + r"'.*?(?<!\\)'", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
continue
# Something I can't parse: advance one char and hope for the best
tok, src = src[0], src[1:]
yield tok
def _usematch(m, inp):
return m.group(), inp[m.end():] # Matched chunk & remaining input
# To recognize an sql command, it MUST begin with one of these words
sql_commands = set("select insert update delete create drop alter declare".split())
def is_sql_string(tok):
if not php_mode or len(tok) < 3 or tok[0] not in set("\"'"):
return False
tokwords = tok[1:-1].split()
return tokwords and tokwords[0].lower() in sql_commands
for fname in sys.argv[1:]:
processfile(fname)

In PHPStorm you can specify SQL dialect for your project: http://www.jetbrains.com/phpstorm/webhelp/sql-dialects.html
Next, you must setup Data Source: http://www.jetbrains.com/phpstorm/webhelp/data-sources-2.html
After that your IDE will support SQL syntax and autocomplete for tables (fields).
Also, there is a page, where you can specify SQL code-style: http://www.jetbrains.com/phpstorm/webhelp/code-style-sql.html

There is no such IDE.
Maybe some SQL is broken into multiple string concatenation, or maybe some SQL is generated using some iterator. Or maybe it contains invalid SQL such as {$_SESSION['admin_id']}.
Your only chance is writing a small script, tuned to match the coding style and possible invalid SQL stuff, which will repair all application source code files. It will take you hours to get it right, but in the end you won't need an IDE which doesn't exist, and you will have a prettyfiend stonified SQL and better source code.
(The above is a solution, thinking you have hundreds of SQL statement throughout the app; if not, just repair them by hand).
Edit: make sure you log all changes in a comparison table, so you can review all which was formatted by your script.

may be nuSphere debugger somehow help you for doing this here is the link nuSphere

Write your queries in MySQL Workebench then edit->format->beautify query
Then paste the query into netbeans, select the test and tab in.

I always used SQLyog to format my SQL statements and paste them back to the IDE, because i didn't find an IDE either, which is able to format sql inside php blocks.

I built a tool to do this for MS SQL Server and C# code. I'd be happy to alter the tool for this purpose for a small fee.
http://www.softfrontiers.com/Downloads/ReIndenter.shtml
An hour or two of my time will save you many hours of frustration.

You can use the tokenizer extension to write a script that would format the SQL.
The following script can be invoked from the command-line, it reads from standard input and writes to standard output. It handles both quoting styles (double or single quotes).
All strings are scanned for possible SQL grammar, based on the starting word, and line breaks are inserted before every keyword; both starting word and keywords are extensible, so go wild :)
<?php
$tokens = token_get_all(file_get_contents('php://stdin'));
function token_value($token)
{
return is_array($token) ? $token[1] : $token;
}
function sql_format($s)
{
if (preg_match("/^(?:select|insert|update|delete)/i", $s)) {
// prefix newline and tab before every keyword
return preg_replace('/\b(from|where|and|order|group by)/i', "\n\t\\0", $s);
}
return $s;
}
$target = '';
$i = 0; $n = count($tokens);
while ($i < $n) {
$token = $tokens[$i];
if ($token === '"') {
$s = ''; ++$i;
while ($i < $n && $tokens[$i] !== '"') {
$s .= token_value($tokens[$i]);
++$i;
}
if ($i < $n) {
++$i;
}
$target .= '"' . sql_format($s) . '"';
} elseif (is_array($token) && $token[0] === T_CONSTANT_ENCAPSED_STRING) {
$quote_style = $token[1][0];
$target .= $quote_style . sql_format(trim($token[1], "'\"")) . $quote_style;
++$i;
} else {
$target .= token_value($token);
++$i;
}
}
echo $target;

You asked:
Is there any program IDE or not that can format MySQL code inside PHP string
with specifically this PHP string definition:
$request1 = "select * from tbl_admin where admin_id= {$_SESSION['admin_id']} and active= 1 order By admin_id Asc";
And the answer is no. There doesn't exist a well use-able settop on a PHP parser in IDEs or on the commandline that works PHP's token_get_all.
With token_get_all you should be able to first of all extract that part that makes sense in your case to be edited. Here with context:
<309:T_VARIABLE> "$request1" <371:T_WHITESPACE> " " "=" <371:T_WHITESPACE> " " """ <314:T_ENCAPSED_AND_WHITESPACE> "select * from tbl_admin where admin_id= " <375:T_CURLY_OPEN> "{" <309:T_VARIABLE> "$_SESSION" "[" <315:T_CONSTANT_ENCAPSED_STRING> "'admin_id'" "]" "}" <314:T_ENCAPSED_AND_WHITESPACE> " and active= 1 order By admin_id Asc" """ ";"
As these tokens show, there is a lot of additional work going to extract that what you call string from it:
$request1 = "select * from tbl_admin where admin_id= {$_SESSION['admin_id']} and active= 1 order By admin_id Asc"
This need to be managed and identified in tokens:
<314:T_ENCAPSED_AND_WHITESPACE> "select * from tbl_admin where admin_id= " <375:T_CURLY_OPEN> "{" <309:T_VARIABLE> "$_SESSION" "[" <315:T_CONSTANT_ENCAPSED_STRING> "'admin_id'" "]" "}" <314:T_ENCAPSED_AND_WHITESPACE> " and active= 1 order By admin_id Asc"
As this example shows, this is not true SQL. So you not only need to find a SQL parser (which exists in PHP, see Parsing sql query PHP), but you also need to make that SQL parser aware of PHP variable substitution like {$_SESSION['admin_id']} in your case. For you it is a variable, for an SQL parser this is just a freaky syntax soup if not an error.
Your small code example is a good one: It already shows that there is no information about the nature of the string that will be substituted. As this information is hidden, a SQL parser will never be able to deal with this string as something well-formed.
So to make my answer "No" more profound: Because no general tools on how to deal with multiple outcome on the higher languages level (the PHP string has multiple probably correct representations in SQL, only the author of the variable content will can tell which one is correct) that already exists, there is no general solution available.
You might want to just fire up some regular expressions on your codebase and blitzshit together an outcome you can feel happy with, and indeed the tools ehime lined-up are worth to consider.
But probably it's worth to invest the time and first extract the strings from the PHP token stream, reformat the string and then proceed outputting the result. That's something perl and regexes can't give you because they don't have the PHP tokenizer.

If there is no support in all the many IDEs for such a thing, there is a reason in most cases. Please consider prepared statements oder object wrappers for your work. I know both things can't be implemented in every system within a few minutes, but your code will become maintainable.
In short: IDEs cant correct design errors. They just make them look nice and colored.

I have used PHPDesigner. i think this will be fulfill what you expecting.

Late to the party, but...
function formatSQL($txt){
$txt = str_replace('SELECT ', "\nSELECT", $txt);
$txt = str_replace(' MATCH', "\nMATCH", $txt);
$txt = str_replace(' AGAINST', "\nAGAINST", $txt);
$txt = str_replace(' OR ', "\nOR", $txt);
$txt = str_replace(' AND ', "\n\tAND ", $txt);
$txt = str_replace(' FROM ', "\nFROM", $txt);
$txt = str_replace(' WHERE ', "\nWHERE", $txt);
$txt = str_replace(' ORDER ', "\nORDER", $txt);
return $txt;
}

Related

Getting different output for same PHP code

(Can't paste the exact question as the contest is over and I am unable to access the question. Sorry.)
Hello, recently I took part in a programming contest (PHP). I tested the code on my PC and got the desired output but when I checked my code on the contest website and ideone, I got wrong output. This is the 2nd time the same thing has happened. Same PHP code but different output.
It is taking input from command line. The purpose is to bring substrings that contact the characters 'A','B','C','a','b','c'.
For example: Consider the string 'AaBbCc' as CLI input.
Substrings: A,a,B,b,C,c,Aa,AaB,AaBb,AaBbC,AaBbCc,aB,aBb,aBbC,aBbCc,Bb,BbC,BbCc,bC,bCc,Cc.
Total substrings: 21 which is the correct output.
My machine:
Windows 7 64 Bit
PHP 5.3.13 (Wamp Server)
Following is the code:
<?php
$stdin = fopen('php://stdin', 'r');
while(true) {
$t = fread($stdin,3);
$t = trim($t);
$t = (int)$t;
while($t--) {
$sLen=0;
$subStringsNum=0;
$searchString="";
$searchString = fread($stdin,20);
$sLen=strlen($searchString);
$sLen=strlen(trim($searchString));
for($i=0;$i<$sLen;$i++) {
for($j=$i;$j<$sLen;$j++) {
if(preg_match("/^[A-C]+$/i",substr($searchString,$i,$sLen-$j))) {$subStringsNum++;}
}
}
echo $subStringsNum."\n";
}
die;
}
?>
Input:
2
AaBbCc
XxYyZz
Correct Output (My PC):
21
0
Ideone/Contest Website Output:
20
0
You have to keep in mind that your code is also processing the newline symbols.
On Windows systems, newline is composed by two characters, which escaped representation is \r\n.
On UNIX systems including Linux, only \n is used, and on MAC they use \r instead.
Since you are relying on the standard output, it will be susceptible to those architecture differences, and even if it was a file you are enforcing the architecture standard by using the flag "r" when creating the file handle instead of "rb", explicitly declaring you don't want to read the file in binary safe mode.
You can see in in this Ideone.com version of your code how the PHP script there will give the expected output when you enforce the newline symbols used by your home system, while in this other version using UNIX newlines it gives the "wrong" output.
I suppose you should be using fgets() to read each string separetely instead of fread() and then trim() them to remove those characters before processing.
I tried to analyse this code and that's what I know:
It seems there are no problems with input strings. If there were any it would be impossible to return result 20
I don't see any problem with loops, I usually use pre-incrementation but it shouldn't affect result at all
There are only 2 possibilities for me that cause unexpected result:
One of the loops iteration isn't executed - it could be only the last one inner loop (when $i == 5 and then $j == 5 because this loop is run just once) so it will match difference between 21 and 20.
preg_match won't match this string in one of occurrences (there are 21 checks of preg_match and one of them - possible the last one doesn't match).
If I had to choose I would go for the 1st possible cause. If I were you I would contact concepts author and ask them about version and possibility to test other codes. In this case the most important is how many times preg_match() is launched at all - 20 or 21 (using simple echo or extra counter would tell us that) and what are the strings that preg_match() checks. Only this way you can find out why this code doesn't work in my opinion.
It would be nice if you could put here any info when you find out something more.
PS. Of course I also get result 21 so it's hard to say what could be wrong

How to NOT print a trailing newline after echo "<something>"

For a command line application I am trying to ask a simple question using the following code (example is not real life, code, but resembles the "real" version):
echo "Do you want to quit? [Y]/N";
$handle = fopen ( "php://stdin", "r" );
$input = trim(fgets($handle));
if ( empty($input) ) {
$input = 'Y';
echo "Y\n";
}
The result I want, is the following - When a user does -NOT- provide input:
Do you want to quit? [Y]/N: N // User only hits enter, not 'N'..
What I get is:
Do you want to quit? [Y]/N: // User only hits enter, not 'N'..
N
So the question is: How do I force echo 'Something'; to NOT print a newline after the echo.
Basically I need the equivalent of bash's echo -n '...' (does not print the trailing newline).
To understand why is it so - you need to understand that there are two things: STDIN and STDOUT that are involved into program. And - yes, php does not add new lines. With simple echo "foo"; you'll get exactly "foo", without new line.
But why are you seeing new line then? Simple: because you've pressed "it". That is: you've pressed "enter" key, terminal got it and printed it. Your program, of course, also got it, but at that moment the "key" is already printed.
What can you do? On that step: nothing. It's already done and that's it. You'll see it in your screen. However, yes, there is a trick that I can suggest. You can use stty to maintain behavior, when you can control the input and/or output. Combined with system() you'll get the idea.
Here we are with code:
function emulatePrintable()
{
$result = '';
while($c = trim(fgetc(STDIN)))
{
echo($c);
$result.=$c;
}
return $result;
}
system('stty -echo');
echo("Do you want to quit? [Y]/N ");
$result = emulatePrintable();
if($result==='')
{
echo("You didn't type anything!");
}
echo "\n"; //<--- this is to delimit program's end of work
system('stty echo');
What's happening? You're doing this:
Suppress any input printing with stty -echo. This is the trick. You're suppressing only input display, not output display. That is why you'll be able to see echo() strings from PHP
Emulating output for printable characters. That is: you still want to show what user is typing (your Y or N) - but you want to skip new line. Simple emulatePrintable() will do the work (may be not the best name, but at least I've tried)
After you've got the input (it's interrupted with EOL, for example) - you can examine what is it. If it's an empty string, then you've caught it: user typed nothing.
Now, do not forget to enable input display with stty echo - otherwise.. well, you'll end with "non-working" terminal.
Benefit: with this you'll be able even to decide, to print character or not (for example, to restrict only Y and N for output).
So this is the solution for unix-based OS. In Win - best of luck to you. You may check this page for console modes & related stuff, but I'm not sure it will work (since have not tested).

How to parse strings - detailed explanation and information on syntax

I would like to parse a sting of data in a shell script with a simple 1 line expression. But I do not know how or where to find any information describing how it is done. All the examples I can find just looks like an illegal math equations, and I can not find any documentation describing how it works.
First, what exactly is this form of parsing called so I know what I am talking about and what to search for. Secondly, where can I find what it all means so I can learn how to use it correctly and not just copy some one else's work with little understanding of how it works.
/\.(\w+)/*.[0-9]/'s/" /"\n/g;s/=/\n/gp
I recall learning about this in perl a couple decades ago, but have long since forgotten what it all means. I have spent days searching for information on what this all means. All I can find are specific examples with no explanations of what it is technically called and how it works!
I want to separate each field then extract the key name and numerical data in a shell script. I realize some forms of parsing are done differently in shell scripts as opposed to php or perl scripts. But I need to learn the parsing syntax used to filter out the specific data sets that I could use in both, shell and php.
Currently I need to parse a single line of data from a file in a shell script for a set of conditionals required by other support scripts.
#!/bin/sh
Line=`cat ./dump.txt`
#Line = "V:12.46 A:3.427 AV:6.08 D:57.32 S:LOAD CT:45.00 P:42.71 AH:2016.80"
# for each field parse data ("/[A-Z]:[0-9]/}" < $Line)
# $val[$1] = $2
# $val["V"] = "12.46"
# $val["AV"] = "6.08"
if $val["V"] < 11.4
then
~/controls/stop.sh
else
~/controls/start.sh
fi
if $val["AV"] > 10.7
then
echo $val["AV"] > ./source.txt
else
echo "DOWN" > ./source.txt
fi
I need to identify and separate the difference between "V:" and "AV:".
In php I can use foreach & explode into an array. But I am tired of writing half a page of code for some thing that can be done in a single line. I need to learn a simpler and more efficient way to parse data from a string and extract the data in to a usable variable.
$Line = file_get_contents("./dump.txt");
$field = explode (' ' , $Line);
foreach($field as $arg)
{
$val = explode (':' , $arg);
$data[$val[0]] = $val[1];
}
# $data["V"] = "12.46"
# $data["AV"] = "6.08"
A quick shell example is much appreciated, but I really need to know "HOW TO" do this my self. Please give me some links or search criteria to find the definitions and syntax to these parsing expressions.
Thank you in advance for your help.
The parsing patterns you're talking about are commonly referred to as regular expressions or regex.
For php you can find a lot of helpful information from http://au1.php.net/manual/en/book.pcre.php
Regex is quite hard especially for complex expressions so I usually google search for an online regex expression tester. Preferably one which highlights whats being matched. Javascript ones are especially good as the results are instant and the regex syntax is the same for PHP.
Special thanks to James T for leading me in the right direction.
After reading through the regular expressions I have figured out the search pattern I need. Also included is a brief script to test the output. Taking into account that BASH can not use decimal numbers we need to convert it to a whole number. The decimal intigers is always fixed at 2 or 3 places so conversion is easy, just drop the decimal. Also the order in which the fields are recorded remains constant so the order in which they are read will remain the same.
The regular expression that fits the search for each of the first 4 fields is:
\w+:([0-9]+)\.([0-9]+)\s
( ) = the items to search/parse; using 2 searches for each data set "V:12.46"
\w = for the word search and the " + " means any 1 or more letters
: = for the delimiter
( -search set 1:
[0-9] = search any numbers and the " + " means any 1 or more digits
) -end search set 1
\. = for the decimal point in the data
( -search set 2:
[0-9] = search any numbers and the " + " means any 1 or more ( second set after the decimal)
) -end search set 2
\s = white space (blank space)
Now duplicate the search 3 times for the first 3 fields, giving me 6 variables.
\w+:([0-9]+)\.([0-9]+)\s\w+:([0-9]+)\.([0-9]+)\s\w+:([0-9]+)\.([0-9]+)\s
And here is a simple script to test the output:
#!/bin/bash
Line="V:13.53 A:7.990 AV:13.65 D:100.00 S:BulkCharge CT:35.00 P:108.11 AH:2116.20"
regex="\w+:([0-9]+)\.([0-9]+)\s\w+:([0-9]+)\.([0-9]+)\s\w+:([0-9]+)\.([0-9]+)\s"
if [[ $Line =~ $regex ]]; then
echo "match found in $Line"
i=1
n=${#BASH_REMATCH[*]}
while [[ $i -lt $n ]]
do
echo " capture[$i]: ${BASH_REMATCH[$i]}"
let i++
done
Volt=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
Amp=${BASH_REMATCH[3]}${BASH_REMATCH[4]}
AVG=${BASH_REMATCH[5]}${BASH_REMATCH[6]}
else
echo "$Line does not match"
fi
if [ $Volt -gt 1200 ]
then
echo "Voltage is $Volt"
fi
resulting with an output of:
match found in V:13.53 A:7.990 AV:13.65 D:100.00 S:BulkCharge CT:35.00 P:108.11 AH:2116.20
capture[1]: 13
capture[2]: 53
capture[3]: 7
capture[4]: 990
capture[5]: 13
capture[6]: 65
Voltage is 1353

PHP and SQL brings different results

I'm trying to read a list of items from a CSV file, compare it with the items in my database, and generate a newly one with the ones not in my base. From the CSV with thousand results, only 26 were not in db. However, the first item in my new CSV is present in my database, meaning it's a false positive. Only the first item is wrong, all the others are fine (I've queried them all).
Here is my code:
<?php
function generate_diff_csv() {
$conn = new mysqli("localhost","rcpp","*********", "items");
$key_ref = fopen("INV14.csv", "r");
$not_in = fopen("not_in.csv","w");
[...]
fclose($key_ref);
$keys = array();
foreach ($custom1 as $custom) {
$trimmed_custom = trim($custom);
$result = $conn->query("SELECT custom1 FROM products WHERE custom1 = '{$trimmed_custom}'");
if($result->num_rows == 0) {
$keys[] = array("key" => $trimmed_custom);
echo "adicionado ao csv... \n";
}
}
foreach($keys as $key) {
fputcsv($not_in, $key);
}
fclose($not_in);
$conn->close();
}
generate_diff_csv();
To be sure I had everything right, I created a temporary table with the data I needed to compare. When I query it with an SQL, I get the 25 results. Putting them (PHP x SQL) side-by-side in a file, only the first is not a match, meaning it is really the only wrong result.
SELECT ref FROM refs WHERE ref NOT IN (SELECT custom1 FROM products);
Why is that? Why PHP returns the 1st key on my query?
The PHP is being executed from the command line, PHP 5.4.12 (Windows). I haven't tested on the Linux production environment, but I don't believe this would be a platform specific issue.
Thank you in advance.
Well, first of all, depending on the collation in the database, table and field, SQL Might be ignoring letter case, so for SQL, "something" is identical to "SoMEthIng". Also, since my practice with SQL CHAR() value types, it has come to my attention that suffix spaces are also ignored in comparison, at least when it comes to CHAR().
I've solved the problem. And it was a platform problem, but not related with PHP (I think).
I was running the script through cmd, not Powershell, and the first item was getting an additional UTF BOM header on the first character. My fault was to not pay attention to the first output, thinking it was just cmd pritting some rubbish characters. But when I used var_dump($custom1), I could see that those characters were being put inside the variable and trim wasn't cleaning it.
The solution was to remove BOM from CSV input file.
Link reference (for the BOM character issue): https://superuser.com/questions/601282/is-not-recognized-as-an-internal-or-external-command --- first answer explains why 'cmd' outputs those characters.

Interactive shell using PHP

Is it possible to create an interactive shell, using PHP alone?
I mean something like you have with databases, Python, etc. If it is, how?
Yes, it's possible. In order to be interactive, the program must be able to wait for and read in user input from stdin. In PHP, you can read from stdin by opening a file descriptor to 'php://stdin'. Taken from an answer to different question, here's an example of an interactive user prompt in PHP (when run from the command line, of course):
echo "Continue? (Y/N) - ";
$stdin = fopen('php://stdin', 'r');
$response = fgetc($stdin);
if ($response != 'Y') {
echo "Aborted.\n";
exit;
}
Of course, to get a full line of input rather than a single character, you'd need fgets() instead of fgetc(). Depending what your program/shell will do, the whole program might be structured as one big continuous loop. Hopefully that gives you an idea how to get started. If you wanted to get really fancy (CLI pseudo-GUI), you could use ncurses.
Since this question has been asked and answered, a better solution has been added to PHP. In all recent PHP versions, at least PHP 5.4, you can easily get user input as so:
$input = fgets(STDIN);
The way I understand your question you just want the PHP interpreter to run on the command line so you that it will evaluate any PHP code that you type. I use that feature of Python all the time to test code snippets. In which case I believe the answer you are looking for is to execute (from the command line):
php -a
Assuming PHP is in your path this will drop you in to the PHP interpreter, like it does on mine:
php -a
Interactive shell
php >
From there you can start to evaluate arbitrary PHP expressions and see the results:
php > $a = 'abcdef';
php > echo strlen($a);
6
Here's an expanded take on this. I've added an isCLI() check in case you're run your script both in CLI and on a web server. Otherwise the server could loop using my function. This solution will prompt the user, check the input, and re-prompt the user for fixed input if necessary.
I rtrim() the input, because if the user uses return to submit their entry, that may be appended to the entry. Validation is not necessary; just don't pass a function in that case.
function isCLI() {
return (php_sapi_name() === 'cli' OR defined('STDIN'));
}
function userPrompt($message, $validator=null) {
if (!isCLI())
return null;
print($message);
$handle = fopen ('php://stdin','r');
$line = rtrim(fgets($handle), "\r\n");
if (is_callable($validator) && !call_user_func($validator, $line)) {
print("Invalid Entry.\r\n");
return userPrompt($message, $validator);
} else {
print("Continuing...\r\n");
return $line;
}
}
// Example =====================
function validateSetLangCode($str) {
return preg_match("/^[A-Z0-9]{3}-[A-Z]{2}$/", $str);
}
$code = userPrompt("Please enter the set / language codes. Use the format 'SET-EN', where SET is the three-letter set code and EN is the two-letter lang code. \r\n", 'validateSetLangCode') ?: 'SET-EN';
var_dump($code);
Since PHP has a built-in Unix-only function readline() to do exactly that, note:
We can use and hold the result of readline in a variable.
#!/usr/bin/php
<?php
$user = readline("List dir [l] | Say hello [h] | exit [q]: ");
if ($user === "l"){ system("ls"); }
if ($user === "h"){ echo "Hello!"; }
if ($user === "q"){ exit; }
echo "\nThanks!";
Example output:
l ls result
h «hello»
q exit
Ctrl + C exit.
Ctrl + D with empty input, continue to the next sequence. «Thanks». $user is defined and empty, no error.
Ctrl + D with some input: No action. Still waiting for input.
Ctrl + M Continue and take the current input in $user.
Ctrl + J Continue and take the current input in $user, same behavior as Ctrl + M.
Return continue to the next sequence «Thanks». $user can stay empty, no error.
Ctrl + Z may be used to cancel a loop and move to the top one. $user will be unset if the var is not defined in this scope.
Depending input, we can define empty values using!empty or do more surgical testings (the readline response can be many chars).
$user can be tested with !isset if not yet asked.
There is also the built-in readline_add_history() to store the user input into an object, where values can be retrieved directly by their name (nice for code clarity):
readline_add_history($user);
print_r(readline_list_history());
print_r(readline_user());
It is very useful to build real complex stuffs!
See how to catch and send POSIX signals.
PHP function readline()
If you want the interactive shell to process PHP commands, one example is phpsh which was apparently created at Facebook, but it is written in Python.
I know the questioner didn't want the second option, but for those that wanted the second option as I did, in addition to phpsh, PHP also has its own shell:
Just run php -a.
Check out Sheldon.
It's pretty easy to get started. It includes Symfony 2 and Zend Framework libraries that do a lot of the basic console I/O work and gives you a higher-level abstraction built around command objects (with regex routes) and Contexts (which hold immutable state).
One of the things I love is that "out of the box", your application can run as either an interactive shell, or as a standard script that you can run from the command line, specify a command, pass any arguments, and when the command is finished the application exits.

Categories