Fseek adds NUL = \u0 characters to the output file - php

Iam creating a simple PHP application, where is a csv file upload then an .stm(its a simple text file) file download. The records must be write at given byte position. For example: 1st record position 1, length 2, 2nd record, etc.Records
So Im trying to use fwrite, fseek to get to given position, for example I dont need 2 record to be filled, so I jump to position 11 but there are NUL characters in the file.
Code:
$input = $sFileName;
//a nevbol kiszedni a datumot, majd EEEEHHNN verziora konvertalni
$get_date_from_name = str_replace(".","",substr($sFileName,0,10));
$output = $get_date_from_name . '_mpl_tensoft_import.stm';
$_SESSION['file_name'] = $output;
if (false !== ($ih = fopen($input, 'r'))) {
$oh = fopen($output, 'w+b');
//Create first line of the file 11 record type
fwrite($oh,"11");
fseek($oh, 11);
fwrite($oh,"120967120159857100100007");
/*while (false !== ($data = fgetcsv($ih,0,";"))) {
// this is where you build your new row
//Interne cislo, Dodavatel, Dodavacie c.faktury Celk.suma, Dátum prijatia, Dátum splat. = Datum uhrady, Predmet
$outputData = array($data[0], $data[1], $data[2], $data[3], $data[12], $data[13], $data[36] );
fputcsv($oh, $outputData);
}*/
fclose($ih);
fclose($oh);
unlink($input);
}
Result is:
11NULNULNULNULNULNULNULNULNUL120967120159857100100007
Visual Studio Code gives an error that the file is binary or to large or uses an unsupported encoding.
Notepad++ adds the NUL characters.
Should I just use a whitespace character? 1 whitespace character equals 1 byte? The file should be in CP852 encoding
Thanks for the help and pointing in to the right direction.

Your seek() offset seems to be "out of range".
Documentation said :
In general, it is allowed to seek past the end-of-file; if data is then written, reads in any unwritten region between the end-of-file and the sought position will yield bytes with value 0.
EDIT :
If you want to put the second number at offset 13, using spaces, you could do something like this :
$ban_pos = 13 ;
$num = "11" ;
$pos = $ban_pos - strlen($num) ;
$ban = "120967120159857100100007" ;
$oh = fopen($output, 'w+');
fwrite($oh, $num);
fwrite($oh, str_repeat(' ', $pos));
fwrite($oh, $ban);
fclose($oh);
The file will contains :
11 120967120159857100100007

Related

Removing A Specific Line From A File

I have a text file like this:
1
2
3
4
5
6
7
8
9
10
And I want to remove specific lines which numbers are in an array like this:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
//wanna remove these lines
So I tried this code but It didn't work and It just doubles the text and ruins everything:
<?php
$myfile='txt.txt';
$remove=array(1,3,5,7,10);
$lines=file($myfile);
$countline=sizeof($lines);
$data=file_get_contents($myfile);
for ($i=0; $i < $countline+1; $i++) {
if (in_array($i, $remove)) {
$editeddata=str_replace($lines[$i], "", $data);
$removeline = file_put_contents($myfile, $editeddata.PHP_EOL , FILE_APPEND | LOCK_EX);
}
}
?>
I couldn't use ((for)) properly and I think it will just ruin the text because it deletes lines one after another have been deleted and it changes the order so I should have a code to remove them all at once.
And please don't give a code to just replace numbers because the main text file is not only numbers and contains word,etc...
Thanks A lot!
You're reading the file twice (with file and file_get_contents), which I think is confusing the later code. You have everything you need with the first call - an array of all the lines in the file. You're also using str_replace to remove the content, which seems a bit dangerous if any of the content is repeated.
I'd refactor this to simply filter the array of lines based on their line-number, then write it back to the file in a single operation:
$myfile = 'txt.txt';
$remove = [1, 3, 5, 7, 10];
// Read file into memory
$lines = file($myfile);
// Filter lines based on line number (+1 because the array is zero-indexed)
$lines = array_filter($lines, function($lineNumber) use ($remove) {
return !in_array($lineNumber + 1, $remove);
}, ARRAY_FILTER_USE_KEY);
// Re-assemble the output (the lines already have a line-break at the end)
$output = implode('', $lines);
// Write back to file
file_put_contents($myfile, $output);
If the file fits in memory then you can do the simple:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
file_put_contents($myfile, implode(PHP_EOL,array_diff($file($myfile,FILE_IGNORE_NEW_LINES), $remove)));
Note: Because it's a bit ambiguous whether $remove has the content or the lines you want to remove, the above code removes the content . If you want to remove lines change array_diff($file($myfile,FILE_IGNORE_NEW_LINES), $remove) to array_diff_keys($file($myfile,FILE_IGNORE_NEW_LINES), array_flip($remove))
If your file is large then you need to resort to some sort of streaming. I suggest against reading and writing to the same file and doing something like:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
$h = fopen($myfile,"r");
$tmp = fopen($myfile.".tmp", "w");
while (($line = fgets($h)) !== false) {
if (!in_array(rtrim($line, PHP_EOL), $remove)) {
fwrite($tmp, $line);
}
}
fclose($h);
fclose($tmp);
unlink($myfile);
rename($myfile.".tmp", $myfile);

I have a word doc. i want to get word count per page of word doc?

i could only find solution for per line but cant find page break; also confused a lot.
for docx also cant find exact word count.
function read_doc($filename) {
$fileHandle = fopen($filename, "r");
$line = #fread($fileHandle, filesize($filename));
$lines = explode(chr(0x0D), $line);
$outtext = "";
foreach ($lines as $key => $thisline) {
if( $key > 11 ){
var_dump($thisline);
$pos = strpos($thisline, chr(0x00));
if (($pos !== FALSE) || (strlen($thisline) == 0)) {
continue;
} else {
var_dump($thisline);
$text = preg_replace("/[^a-zA-Z0-9\s\,\.\-\n\r\t#\/\_\(\)]/", "", $thisline);
var_dump($text);
}
}
}
return $outtext;
}
Implementing your own code for this doesn't sound like a good idea. I would recommend using an external library such as PHPWord. It should allow you to convert the file to plain text. Then, you can extract the word count from it.
Also, an external library such as that adds support for a number of file formats, not restricting you to Word 97-2003.
Here's a basic piece of VB.NET code that counts words per page but be aware it depends on what Word considers to be a word, it is not necessarily what a user considers a word. In my experience you need to properly analyse how Word behaves, what it interprets and then build your logic to ensure that you get the results that you need. It's not PHP but it does the job and can be be a starting point for you.
Structure WordsPerPage
Public pagenum As String
Public count As Long
End Structure
Public Sub CountWordsPerPage(doc As Document)
Dim index As Integer
Dim pagenum As Integer
Dim newItem As WordsPerPage
Dim tmpList As New List(Of WordsPerPage)
Try
For Each wrd As Range In doc.Words
pagenum = wrd.Information(WdInformation.wdActiveEndPageNumber)
Debug.Print("Word {0} is on page {1}", wrd.Text, pagenum)
index = tmpList.FindIndex(Function(value As WordsPerPage)
Return value.pagenum = pagenum
End Function)
If index <> -1 Then
tmpList(index) = New WordsPerPage With {.pagenum = pagenum, .count = tmpList(index).count + 1}
Else
' Unique (or first)
newItem.count = 1
newItem.pagenum = pagenum
tmpList.Add(newItem)
End If
Next
Catch ex As Exception
WorkerErrorLog.AddLog(ex, Err.Number & " " & Err.Description)
Finally
Dim totalWordCount As Long = 0
For Each item In tmpList
totalWordCount = totalWordCount + item.count
Debug.Print("Page {0} has {1} words", item.pagenum, item.count)
Next
Debug.Print("Total word count is {0}", totalWordCount)
End Try
End Sub
When you unzip .doc or .docx file, you will get folder. Look for document.xml file in word subfolder. You will get whole document with xml syntax. Split string by page xml syntax, Strip xml syntax and use str_word_count.
What is figure out that i will need a windows server :-- using COM object ;;
Please check this link
https://github.com/lettertoamit/MS-Word-PER-PAGE-WORDCOUNT/blob/master/index.php

Printing text file contents into columns

I have this text file:
https://drive.google.com/file/d/0B_1cAszh75fYSjNPZFRPb0trOFE/view?usp=sharing
I can print it using the following code:
$file = fopen("gl20160630.txt","r");
while(! feof($file))
{
echo fgets($file). "<br />";
}
fclose($file);
But it looks like this:
I want the contents of this text file to be separated into four columns -Line, Description, Legacy GL Code and Closing Balance. If any one of these columns is empty it should remain empty. I just want to print those lines that start with ====>
Could you please help me find a way to print the text file like the way I want?
It's actually pretty simple, since your file has a strict number of character for each column.
All you need to do is a substr on each line starting by '====>{line}', then you can read each column by there position in the file.
Here is an example using your file :
$file = fopen("gl20160630.txt","r");
while(! feof($file))
{
$fullLine = fgets($file);
$line = substr($fullLine, 5, 4);
if (is_numeric($line)) {
$liability = trim(substr($fullLine, 10, 30));
$legacy = trim(substr($fullLine, 40, 39));
$balance = trim(substr($fullLine, 79, 15));
if ($liability != null && $legacy != null && $balance != null)
echo $line." ".$liability." ".$legacy." ".$balance."\n";
}
}
fclose($file);
You can see that all I do is:
check if the character in the column 'Line' are numbers
then I get all the other element
I 'clean' them by getting rid of unwanted characters (spaces, ...) with trim
After that, I check that all elements are filed
And I finally display them
I hope that this will help you, have a nice day ;)

php fgets, fwrite and newline

Using php fgets function , I am reading from one file, file "A" which is in a particular format and I am writing to another file, file "B" in a particular format using fwrite.
However, no matter what new lines or line breakers I put, some characters keep being misplaced.
Below is the format I wish to see in the new file, file B:
ICCID,IMSI,KI,ESN,PIN1,PUK1,PIN2,PUK2,IMSI2,KI2,ACC_NBR,NAI_USERNAME,NAI_PASS
8926003010422000616F,,,645030142200061,2064,16002217,4029,34594354,,,,,
8926003010422000624F,,,645030142200062,8678,91445678,5351,06417774,,,,,
8926003010422000632F,,,645030142200063,0356,51052167,6976,27210792,,,,,
8926003010422000640F,,,645030142200064,5504,38104570,4917,61385706,,,,,
8926003010422000657F,,,645030142200065,7158,23625228,2726,13487033,,,,,
8926003010422000665F,,,645030142200066,3922,52488665,6014,33705660,,,,,
BUT below is exactly what I am getting:
ICCID,IMSI,KI,ESN,PIN1,PUK1,PIN2,PUK2,IMSI2,KI2,ACC_NBR,NAI_USERNAME,NAI_PASS
8926003010422000608F,,,645030142200060,3741,26564507,7283,13507659
,,,,,8926003010422000616F,,,645030142200061,2064,16002217,4029,34594354
,,,,,8926003010422000624F,,,645030142200062,8678,91445678,5351,06417774
,,,,,8926003010422000632F,,,645030142200063,0356,51052167,6976,27210792
,,,,,8926003010422000640F,,,645030142200064,5504,38104570,4917,61385706
,,,,,8926003010422000657F,,,645030142200065,7158,23625228,2726,13487033
,,,,,,,,,,,,,,,,,
you will notice the characters ,,,,, get put at the start of a line rather than the end where I want them to be. Notice also the last line gets to be ,,,,,,,,,,,,,,,,,. Not needed at all.
Below is the code that reads and writes. Needing someone to help me sort out this.
$headStockin= "ICCID,IMSI,KI,ESN,PIN1,PUK1,PIN2,PUK2,IMSI2,KI2,ACC_NBR,NAI_USERNAME,NAI_PASSWORD"."\r\n";
$file = fopen($inputFile, "r"); // reading input file
$myStockinfile = fopen($inputFile."_StockIn.txt", "wb") or die("Unable to create/open a file!");
fwrite($myStockinfile, $headStockin);
$thr=",,,";
$one=",";
$fiv=",,,,,";
$lineNo = 0;
$startLine = 21;
while(!feof($file)){
$lineNo++;
$line = fgets($file);
if ($lineNo >= $startLine) {
$result = explode(" ", $line);
$in= $result[2].$thr.$result[1].$one.$result[3].$one.$result[5].$one.$result[4].$one.$result[6].$fiv;
echo $in; //to see output on html
fwrite($myStockinfile,$in);
}
}
fclose($file);
fclose($myStockinfile);
}
INPUT FILE BELOW
*
********************************************************************************
* HEADER DESCRIPTION
********************************************************************************
*
Quantity: 5000
*
********************************************************************************
* INPUT VARIABLES
********************************************************************************
*
var_in_list:
IMSI: 645030142200060
Ser_Nb: 8926003010422000608F
*
********************************************************************************
* OUTPUT VARIABLES
********************************************************************************
*
var_out:MSISDN/IMSI/ICCID/PIN1/PIN2/PUK1/PUK2
+260950605404 645030142200060 8926003010422000608F 3741 7283 26564507 13507659
+260950605411 645030142200061 8926003010422000616F 2064 4029 16002217 34594354
+260950605412 645030142200062 8926003010422000624F 8678 5351 91445678 06417774
+260950605416 645030142200063 8926003010422000632F 0356 6976 51052167 27210792
+260950605418 645030142200064 8926003010422000640F 5504 4917 38104570 61385706
+260950605421 645030142200065 8926003010422000657F 7158 2726 23625228 13487033
The misplaced commas are because fgets() returns a string that includes the newline at the end. So $fesult[6] has a newline at the end, so $fiv gets put onto the next line. The solution is to trim the input before exploding, and then write a newline in your output.
The extra line is because you're testing for EOF before reading the line. feof() isn't detected until after you read the end of the file.
So change your loop to:
while ($line = fgets($file)) {
$lineNo++;
if ($lineNo < 21) { // Skip first 20 lines
continue;
}
$line = rtrim($line);
$result = explode(" ", $line);
$in= $result[2].$thr.$result[1].$one.$result[3].$one.$result[5].$one.$result[4].$one.$result[6].$fiv.PHP_EOL;
echo $in;
fwrite($myStockinfile, $in);
}

PHP to delete lines within text file beginning with 0 or a negative number

Thank you for taking the time to read this and I will appreciate every single response no mater the quality of content. :)
Using php, I'm trying to create a script which will delete several lines within a text file (.txt) if required, based upon whether the line starts with a 0 or a negative number. Each line within the file will always start with a number, and I need to erase all the neutral and/or negative numbers.
The main part I'm struggling with is that the content within the text file isn't static (e.g. contain x number of lines/words etc.) Infact, it is automatically updated every 5 minutes with several lines. Therefore, I'd like all the lines containing a neutral or negative number to be removed.
The text file follows the structure:
-29 aullah1
0 name
4 username
4 user
6 player
If possible, I'd like Line 1 and 2 removed, since it begins with a neutral/negative number. At points, there maybe times when there are more than two neutral/negative numbers.
All assistance is appreciated and I look forward to your replies; thank you. :) If I didn't explain anything clearly and/or you'd like me to explain in more detail, please reply. :)
Thank you.
Example:
$file = file("mytextfile.txt");
$newLines = array();
foreach ($file as $line)
if (preg_match("/^(-\d+|0)/", $line) === 0)
$newLines[] = chop($line);
$newFile = implode("\n", $newLines);
file_put_contents("mytextfile.txt", $newFile);
It is important that you chop() the newline character off of the end of the line so you don't end up with empty space. Tested successfully.
Something on these lines i guess, it is untested.
$newContent = "";
$lines = explode("\n" , $content);
foreach($lines as $line){
$fChar = substr($line , 0 , 1);
if($fChar == "0" || $fChar == "-") continue;
else $newContent .= $line."\n";
}
If the file is big, its better to read it line by line as:
$fh_r = fopen("input.txt", "r"); // open file to read.
$fh_w = fopen("output.txt", "w"); // open file to write.
while (!feof($fh_r)) { // loop till lines are left in the input file.
$buffer = fgets($fh_r); // read input file line by line.
// if line begins with num other than 0 or -ve num write it.
if(!preg_match('/^(0|-\d+)\b/',$buffer)) {
fwrite($fh_w,$buffer);
}
}
fclose($fh_r);
fclose($fh_w);
Note: Err checking not included.
file_put_contents($newfile,
implode(
preg_grep('~^[1-9]~',
file($oldfile))));
php is not particularly elegant, but still...
Load whole line into variable trim it and then check if first letter is - or 0.
$newContent = "";
$lines = explode("\n" , $content);
foreach($lines as $line){
$fChar = $line[0];
if(!($fChar == '0' || $fChar == '-'))
$newContent .= $line."\n";
}
I changed malik's code for better performance and quality.
Here's another way:
class FileCleaner extends FilterIterator
{
public function __construct($srcFile)
{
parent::__construct(new ArrayIterator(file($srcFile)));
}
public function accept()
{
list($num) = explode(' ', parent::current(), 2);
return ($num > 0);
}
public function write($file)
{
file_put_contents($file, implode('', iterator_to_array($this)));
}
}
Usage:
$filtered = new FileCleaner($src_file);
$filtered->write($new_file);
Logic and methods can be added to the class for other stuff, such as sorting, finding the highest number, converting to a sane storage method such as csv, etc. And, of course, error checking.

Categories