I have some .php files in a directory that calls a user defined function:
_l($string);
each time different string is passed to that function and all strings are static, (i.e. not a single string is entered by user input).
Now I want a script that can list down all the strings form all the files of that directory, which are passed into _l($string);
I had tried:
$fp = fopen($file, "r");
while(!feof($fp)) {
$content .= fgets($fp, filesize($file));
if(preg_match_all('/(_l\(\'.*?\'\);)/', fgets($fp, filesize($file)), $matches)){
foreach ($matches as $key => $value) {
array_push($text, $value[0]);
}
}
}
I get strings but not every strings those are in files, some strings are not match with given regex, so what are the condiotion that is required to get all the strings?
This is easier to get strings in double " or single ' quotes as the _l() function argument.
$string = file_get_contents($file);
preg_match_all('/_l\([\'"](.*?)[\'"]\);/', $string, $matches);
$text = $matches[1];
If needed you can add some optional spaces before and after the ( and before the ):
'/_l\s*\(\s*[\'"](.*?)[\'"]\s*\);/'
Also, if the function can be used in a loop or if or something where it's not terminated by a semi-colon ; then remove it from the pattern.
Related
I have a Text.xml file with some text and the bibliographic references in this text. Its look like this:
Text.xml
<p>…blabla S.King (1987). Bla bla bla J.Doe (2001) blabla bla J.Martin (1995) blabla…</p>
And I have a Reference.txt file with list of bibliographic references and ID number for each reference. Its look like this:
Reference.txt
b1#S.King (1987)
b2#J.Doe (2001)
b3#J.Martin (1995)
I would like to find all bibliographic references from Reference.txt into Text.xml and then add a tag with ID. The goal is TextWithReference.xml who must look like this:
TextWithReference.xml
<p>…blabla <ref type="biblio" target=“b1”>S.King (1987)</ref>. Bla bla bla <ref type="biblio" target=“b2”>J.Doe (2001)</ref> blabla bla <ref type="biblio" target=“b3”>J.Martin (1995)</ref> blabla…</p>
To do this, I use a php file.
Search&Replace.php
<?php
$handle = fopen("Reference.txt","r");
while(!feof($handle))
{
$ligne = fgets($handle,1024);
$tabRef[] = $ligne;
}
fclose($handle);
$handleXML = fopen("Text.xml","r");
$fp = fopen("TextWithReference.xml", "w");
while(!feof($handleXML))
{
$ligneXML = fgets($handleXML,2048);
for($i=0;$i<sizeof($tabRef);$i++)
{
$tabSearch = explode('/#/',$tabRef[$i]);
$xmlID = $tabSearch[0];
$searchString = trim($tabSearch[1]);
if(preg_match('/$searchString/',$ligneXML))
{
$ligneXML = preg_replace('/($searchString)/','/<ref type=\"biblio\" target=\"#$xmlID\">\\0</ref>/',$ligneXML);
}
}
fwrite($fp, $ligneXML);
}
fclose($handleXML);
fclose($fp);
?>
The problem is that this php script just copy Text.xml in TextWithReference.xml without identifing the bibliographic references and without adding the tags…
Many thanks for your help!
There are a number of problems with your code.
The search strings contain characters that are special in regular expressions, such as parentheses. You need to escape these if you want to match them literally. The preg_quote function does this.
Your file-reading loops are not correct. while (!feof()) is not the correct way to read through a file, because the EOF flag isn't set until after you read at the end of the file. So you'll go through the loops an extra time. The proper way to write this is while ($ligne = fgets()).
You have single quotes around the strings where you're trying to substitute $searchString and $xmlID. Variables are only substituted inside double quotes. See What is the difference between single-quoted and double-quoted strings in PHP?
You don't need to put / delimiters around the replacement string in preg_replace.
It's inefficient to explode, trim and escape the lines from the Reference.txt every time you're processing a line in Text.xml. Do it once when you're reading Reference.txt.
In the replacement string, use $0 to replace with the matched text from the source. \0 is an obsolete method that isn't recommended.
You don't need parentheses around the search string in the regexp, since you're not using the $1 capture group in the replacement. And since it's around the whole regexp, it's the same as $0.
Here's the working rewrite:
<?php
$handle = fopen("Reference.txt","r");
$tabRef = array();
while($ligne = trim(fgets($handle,1024))) {
list($xmlID, $searchString) = explode('#', $ligne);
$tabRef[] = array($xmlID, preg_quote($searchString));
}
fclose($handle);
$handleXML = fopen("Text.xml","r");
$fp = fopen("TextWithReference.xml", "w");
while($ligneXML = fgets($handleXML,2048)) {
foreach ($tabRef as $tabSearch) {
$xmlID = $tabSearch[0];
$searchString = $tabSearch[1];
if(preg_match("/$searchString/",$ligneXML)) {
$ligneXML = preg_replace("/$searchString/","<ref type=\"biblio\" target=\"#$xmlID\">$0</ref>",$ligneXML);
}
}
fwrite($fp, $ligneXML);
}
fclose($handleXML);
fclose($fp);
?>
Another improvement takes advantage of the ability to give use arrays as the search and replacement arguments to preg_replace, instead of using a loop. When reading Reference.txt, create the regexp and replacement strings there, and put them each into an array.
<?php
$handle = fopen("Reference.txt","r");
$search = array();
$replacement = array();
while($ligne = trim(fgets($handle,1024))) {
list($xmlID, $searchString) = explode('#', $ligne);
$search[] = "/" . preg_quote($searchString) . "/";
$replacement[] = "<ref type=\"biblio\" target=\"#$xmlID\">$0</ref>";
}
fclose($handle);
$handleXML = fopen("Text.xml","r");
$fp = fopen("TextWithReference.xml", "w");
while($ligneXML = fgets($handleXML,2048)) {
$ligneXML = preg_replace($search,$replacement,$ligneXML);
fwrite($fp, $ligneXML);
}
fclose($handleXML);
fclose($fp);
?>
This is my first post on the internet for some assistance with coding so please bear with me!
I have been finding open code on the internet for a few years and modding it to do what I want but I seem to have come up against a wall with this one that I am sure is very simple. If you would please be able to help me it would be very much appreciated.
I have the following page:
<?php
$text = $_REQUEST['message'];
$f = file_get_contents("all.txt");
$f = explode(", ", $f);
function modFile($pos, $tothis, $inthis)
{
foreach($inthis as $pos => $a){
}
$newarr = implode("\r\n", $inthis);
$fh = fopen("example.txt", "w");
fwrite($fh, $newarr);
fclose($fh);
}
modFile(4, '', $f);
I have a file (all.txt) with the following:
11111111111, 22222222222, 33333333333, 44444444444
That I wish to display like this:
11111111111
22222222222
33333333333
44444444444
and to add a space then some text after each number where the text is the same on each line:
11111111111 text here
22222222222 text here
33333333333 text here
44444444444 text here
I have an html form that passes the custom text to be appended to each line.
I need to keep the file all.txt intact then save the newly formatted file with a different name.
I have tried putting variables into the implode where I currently have the "\r\n" but this does not work.
Any help very much appreciated.
Thanks in advance!
A few notes about your code: You are passing $pos to the function but it will get overwritten in the foreach. Also the foreach is empty, so what's it good for? And I don't see you use $text anywhere either.
To achieve your desired output, try this instead:
file_put_contents(
'/path/to/new.txt',
preg_replace(
'/[^\d+]+/',
' some text' . PHP_EOL,
file_get_contents('all.txt')
)
);
The pattern [^\d+]+ will match any string that is not a consecutive number and replace it with "some text " and a new line.
A somewhat more complicated version achieving the same would be:
file_put_contents(
'/path/to/new.txt',
implode(PHP_EOL, array_map(
function ($number) {
$message = filter_var(
$_POST['message'], FILTER_SANITIZE_SPECIAL_CHARS
);
return sprintf('%s %s', trim($number), $message);
},
array_filter(str_getcsv(file_get_contents('/path/to/all.txt')))
)
));
This will (from the inside out):
Load the content of all.txt and parse it as CSV string into an array. Each array element corresponds to a number.
Each of these numbers is appended with the message content from the POST superglobal (you dont want to use REQUEST).
The resulting array is then concatenated back into a single string where the concatenating character is a newline.
The resulting string is written to the new file.
In case the above is too hard to follow, here is a version using temp vars and no lambda:
$allTxtContent = file_get_contents('/path/to/all.txt');
$numbers = array_filter(str_getcsv($allTxtContent));
$message = filter_var($_POST['message'], FILTER_SANITIZE_SPECIAL_CHARS);
$numbersWithMessage = array();
foreach ($numbers as $number) {
$numbersWithMessage[] = sprintf('%s %s', trim($number), $message);
};
$newString = implode(PHP_EOL, $numbersWithMessage);
file_put_contents('/path/to/new.txt', $newString);
It does the same thing.
Your foreach() closing brace is on the wrong place. You've missed the exact part of running the execution of the new file creation. Here:
$text = $_REQUEST['message'];
$f = file_get_contents("all.txt");
$f = explode(", ", $f);
function modFile($pos, $tothis, $inthis, $text){
$fh = fopen("example.txt", "w");
foreach($inthis as $pos => $a){
$newarr = $a." ".$text."\r\n";
fwrite($fh, $newarr);
}
fclose($fh);
}
modFile(4, "", $f, $text);
This is for formatting your new file as you desire, however, you're not passing the new $text['message'] you want to append to your new file. You could either modify your mod_file() method or pass it within the foreach() loop while it runs.
EDIT* Just updated the whole code, should be now what you aimed for. If it does, please mark the answer as accepted.
I want to parse a comma separated value string into an array. I want to try the str_getcsv() php function but I can't find any good examples on how to use it.
For example I have an input where users submit tags for programming languages (php, js, jquery, etc), like the "tags" input in stackoverflow when you submit a question.
How would I turn an input with example value="php, js, jquery" into an array using str_getcsv?
Its true that the spec at http://us3.php.net/manual/en/function.str-getcsv.php doesn't include a standard example, but the user-submitted notes do a decent job of covering it. If this is a form input:
$val = $_POST['value'];
$data = str_getcsv($val);
$data is now an array with the values. Try it and see if you have any other issues.
I think you should maybe look at explode for this task.
$values = "php, js, jquery";
$items = explode(",", $values);
// Would give you an array:
echo $items[0]; // would be php
echo $items[1]; // would be js
echo $items[2]; // would be jquery
This would probably more efficient than str_getcsv();
Note that you would need to use trim() to remove possible whitespace befores and after item values.
UPDATE:
I hadn't seen str_getcsv before, but read this quote on the manpage that would make it seem a worthwhile candidate:
Why not use explode() instead of str_getcsv() to parse rows?
Because explode() would not treat possible enclosured parts of
string or escaped characters correctly.
For simplicity and readability, I typically find myself using just explode(), only adding in str_getcsv() if the following two conditions are met: 1) the primary delimiter is also used within the data itself; 2) the token that I'm trying to use as the main delimiter is enclosed by another distinct character.
For example, a basic parser for a CSV file:
$filename = $argv[1];
if (empty($filename)) { echo "Input file required\n"; exit; }
$AccountsArray = explode("\n", file_get_contents($filename));
As long as each of the elements of $AccountsArray doesn't embed a "," within the data itself, this will work perfectly and is straightforward and easy to follow:
foreach ($AccountsArray as $entry) {
$acctArr = explode(",", $entry);
}
However, often the data will contain the delimiter, at which point an enclosing token (a " in this example) has to be present. If so, then I switch to str_getcsv() like so:
foreach ($AccountsArray as $entry) {
$acctArr = str_getcsv($entry, ",", "\"");
}
//get the csv
$csvFile = file_get_contents('test.csv');
//separate each line
$csv = explode("\n",$csvFile);
foreach ($csv as $csvLine) {
//separet each fields
$linkToInsert = explode(",",$csvLine);
//echo what you need
//$linkToInsert[0] would be the first field, $linkToInsert[1] second field, etc
echo '• ' . $linkToInsert[1] . '<br>';
}
The code is quite simple, using the Str_getcsv function, we will go
through each line of the CSV file "images.csv" that is located in the
same directory as our script.
NOTE: Functions used are compatible with versions of PHP >= 5.3.0
//First, reading the CSV file
$csvFile = file('file.csv');
foreach ($csvFile as $line) {
$url = str_getcsv($line);
$ch = curl_init($url[0]);
$name = basename($url[0]);
if (!file_exists('directory/' . $name)) {
$fp = fopen('directory/' . $name, 'wb');
}
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}
So, my code generates a CSV file using PHP's built-in fputcsv function.
For the delimiter, I use ',' (a comma).
For the enclosure, I use '"' (a double-quote).
However, when I try something like
fputcsv($file,array('a','b',"long string, with commas",NULL,''),',','"');
it outputs
a,b,"long string, with commas",,
but I would like it to output
"a","b","long string, with commas","",""
Is there an easy way to deal with this, or would I have to write a replacement for fputcsv?
This is not usually a problem for CSV files.
fputcsv puts quotes around the value if it would be ambiguous. For example,
a,b,"long string, with commas",,
is not ambiguous, but,
a,b,long string, with commas,,
is, and will in most (read: all) cases be interpreted by the CSV reader as having more than 5 fields.
CSV parsers will accept string literals even without quotes around them.
If you want quotes around the values anyway, the following snippet would do that. It doesn't escape quotes inside the string - that exercise is left to the reader:
$row = '"' . implode('", "', $rowitems) . '"';
You would want to put this in a loop for all your rows.
I worked around this by inserting some bogus string characters, with a space, ## ##, and then removing them. Here's a sample implementation:
//$exported is our array of data to export
$filename = 'myfile.csv';
$fp = fopen($filename, 'w');
foreach ($exported as $line => $row) {
if ($line > 0) {
foreach ($row as $key => $value) {
$row[$key] = $value."## ##";
}
}
fputcsv($fp, $row);
}
fclose($fp);
$contents = file_get_contents($filename);
$contents = str_replace("## ##", "", $contents);
file_put_contents($filename, $contents);
This encloses all fields in double quotes, including empty ones
I think solution will be like this,
$order_header_arr = array("Item1", "Item2","This is Item3");
fputcsv($fp, $order_header_arr,',',' ');
remember " "[Space] Between third parameter of fputcsv
Any reason you can't str_replace(',,',',"",',$output); ? You'd also have to see if the last or first character is a comma and if so, replace the comma with ,""
fputcsv will not enclose all array variables in quotes. Having a numeric array value without quotes may be correct but presents a problem when a label or address program encounters a numeric defined US zip code because it will strip the leading zeros when printing. Thus 05123-0019 becomes 5123-19.
To enclose all values, whether they exist or not, in quotes I read the input file with fgetsrc and write a corrected version using fwrite. fgetsrc reads the record into array variables. Since fwrite writes a variable, you must string the array variables, enclose them in quotes and separate the array variable with a comma. Then add the record separator.
<?php
// fgetcsv - read array with fgetcsv and string into output variable
// then write with fwrite
// $ar is the array populated from fgetcsv and $arc is the variable strung
// with array variables enclosed in quotes and written using fwrite.
$file_in = fopen("reinOCp.csv","r") or die("Unable to open input file
reinOCp.csv!");
$file_out = fopen("printLABEL.csv", "w") or die("Unable to open output file
prtLABEL!");
while (!feof($file_in)) { //loop through each record of the input file
$ar=fgetcsv($file_in); //read the record into array $ar
if (is_array($ar)){ //this loop will string all the array values plus
// the end of record into variable $arc and then write the variable
$arc = ""; //clear variable $arc
foreach ($ar as $value) {
$arc .= '"' . $value . '",'; // add the array values, enclose in
// quotes with comma separator and store in variable $arc
}
$arc .= "\n"; //add end of record to variable $arc
fwrite($file_out, $arc) or die ("ERROR: Cannot write the file");
//write the record using variable $arc
}
}
echo "end of job";
fclose($file_in);
fclose($file_out);
?>
I was just about to ask the same questions as the question aksed here.... Forcing fputcsv to Use Enclosure For *all* Fields
The question was
When I use fputcsv to write out a line
to an open file handle, PHP will add
an enclosing character to any column
that it believes needs it, but will
leave other columns without the
enclosures.
For example, you might end up with a
line like this
11,"Bob ",Jenkins,"200 main st. USA
",etc
Short of appending a bogus space to
the end of every field, is there any
way to force fputcsv to always enclose
columns with the enclosure (defaults
to a ") character?
The answer was:
No, fputcsv() only encloses the field
under the following conditions
/* enclose a field that contains a delimiter, an enclosure character, or a newline */
if (FPUTCSV_FLD_CHK(delimiter) ||
FPUTCSV_FLD_CHK(enclosure) ||
FPUTCSV_FLD_CHK(escape_char) ||
FPUTCSV_FLD_CHK('\n') ||
FPUTCSV_FLD_CHK('\r') ||
FPUTCSV_FLD_CHK('\t') ||
FPUTCSV_FLD_CHK(' ')
)
There is no "always enclose" option.
I need to create a CSV file will every field enclosed... What would be the best solution?
Thanks in advance...
Roll your own function - its not hard:
function dumbcsv($file_handle, $data_array, $enclosure, $field_sep, $record_sep)
{
dumbescape(false, $enclosure);
$data_array=array_map('dumbescape',$data_array);
return fputs($file_handle,
$enclosure
. implode($enclosure . $field_sep . $enclosure, $data_array)
. $enclosure . $record_sep);
}
function dumbescape($in, $enclosure=false)
{
static $enc;
if ($enclosure===false) {
return str_replace($enc, '\\' . $enc, $in);
}
$enc=$enclosure;
}
(above is using unix style escaping)
C.
A workaround: Supposing you have your data in a 2-dimensional array, you can append a string that will force quoting and you are sure is not contained in your data ("## ##" here) and then remove it:
$fp = fopen($filename, 'w');
foreach ($data as $line => $row) {
foreach ($row as $key => $value) {
$row[$key] = $value."## ##";
}
fputcsv($fp, $row);
}
fclose($fp);
$contents = file_get_contents($filename);
$contents = str_replace("## ##", "", $contents);
file_put_contents($filename, $contents);
I have encountered the same problem, and I have solved it as follows.
I have inserted single quotes to each array value.
This way when you open the csv file with excel, the scientific notation E + 15 will no longer be displayed.
Here I share you as I did.
This worked for me, I hope you do too.
Regards
// this function add a single quote for each member of array
function insertquote($value) {
return "'$value'";
}
# here i send each value of array
# to a insertquote function, and returns an array with new values,
# with the single quote.
foreach ($list as $ferow) {
fputcsv($fp, array_map(insertquote, $ferrow), ';');
}