I am using pdfinfo for getting total number of pages in a pdf file using php.
function getPDFNoOfPages($document) {
$cmd = "C:/wamp/www/PhpProject1/pdfinfo.exe";
exec("$cmd $document", $output);
$pagecount = 0;
foreach ($output as $op) {
// Extract the number
if (preg_match("/Pages:\s*(\d+)/i", $op, $matches) === 1) {
$pagecount = intval($matches[1]);
break;
}
}
return $pagecount;
}
$document = 'test.pdf';
echo getPDFNoOfPages($document);
here my pdf file is in
C:/wamp/www/PhpProject1/test.pdf
but it showing output '0' .how to solve this.thanks in advance
Related
I'm triying to put a text into some pdfs with TCPDI.
It works fine in most pdfs, but in some pdf the code get stuck when it reachs the useTemplate() function, and got 500 error (Maximum time exceded).
They are not long pdf (1,2,3 pages max), and anothers pdfs with more pages works fine. Here is my code:
$pdf = new TCPDI();
$pageCount = $pdf->setSourceFile($path);
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
$templateId = $pdf->importPage($pageNo);
$size = $pdf->getTemplateSize($templateId);
if ($size['w'] > $size['h']) {
$pdf->AddPage('L', array($size['w'], $size['h']));
} else {
$pdf->AddPage('P', array($size['w'], $size['h']));
}
$pdf->useTemplate($templateId); //Here is where it takes so long that it exceeds time
$pdf->SetFont('Helvetica');
$pdf->SetFontSize(10);
$pdf->SetTextColor(255, 0, 0);
$pdf->SetXY(2, 0);
$pdf->Write(0, 'Code nÂș 4');
}
$pdf->Output($file,'D');
Is there any prop of the pdf that can make it stay locked? There are alterntives?
I have a code that process several pdf with this code in a loop an put they into a zip, and when in the chain is one pdf that jam the code the zip obviously dind't process, so if there are a way to detect what pdf are goingo to give me problem, I cant jump over there and generate the zip with the goods one.
I have not control over the pdfs, their are upload by a lot of clients
EDIT: In log there are more than a million of lines similar to PHP Warning: Illegal string offset 'DAmip' in ...\TCPDF\tcpdi_parser.php on line 712 before Maximum execution Time Fatal Error
Same problem for me.
I 'solved' the situation adding the line set_time_limit(10); before the line
while (strspn($data{$offset}, "\x00\x09\x0a\x0c\x0d\x20") == 1) {
I know it's not the right solution but, at least, doesn't block your program
I suggest you to read my comment on GitHub : https://github.com/pauln/tcpdi_parser/pull/23
The function getDictValue() of tcpdi_parser.pdf is incompatible with some PDF files.
All is explained in my response dated of this day.
Suggested modification :
private function getDictValue($offset, &$data) {
$objval = array();
// Extract dict from data
$i = 1;
$dict = "";
$offset+= 2;
$is_bracket = false;
do {
if ($data[$offset] == "[") {
$is_bracket = true;
$dict.= $data[$offset];
} else if ($data[$offset] == "]") {
$is_bracket = false;
$dict.= $data[$offset];
} else if (!$is_bracket && ($data[$offset] == "<") && ($data[$offset + 1] == "<")) {
$i++;
$dict.= "<<";
$offset++;
} else if (!$is_bracket && ($data[$offset] == ">") && ($data[$offset + 1] == ">")) {
$i--;
$dict.= ">>";
$offset++;
} else {
$dict.= $data[$offset];
}
$offset++;
} while ($i > 0);
// Now that we have just the dict, parse it.
$dictoffset = 0;
do {
// Get dict element.
file_put_contents("debug_tcpdi.txt", "getRawObject($dictoffset, data) depuis getDictValue()" . "\r\n", FILE_APPEND);
list($key, $eloffset) = $this->getRawObject($dictoffset, $dict);
if ($key[0] == '>>') {
break;
}
file_put_contents("debug_tcpdi.txt", "getRawObject($eloffset, data) depuis getDictValue()" . "\r\n", FILE_APPEND);
list($element, $dictoffset) = $this->getRawObject($eloffset, $dict);
$objval['/'.$key[1]] = $element;
unset($key);
unset($element);
} while (true);
return array($objval, $offset);
}
I have 2 functions to parse each one a file Excel their sizes are 673K and 131K. They have the same code just their names.
One function it read the data from file Excel and the other function it return:
Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted (Tried to allow 72 bytes)
I have others files Excel their sizes more bigger than this ones and their parsing functions works well.
I want to create a logfile to register every action they do inside the system but I have no idea how to do it. On the other hand I found this solution in Stackoverflow for #Lawrence Cherone:
enter link description here
But the problem is the first time I will do a logfile, I don't know how I create it ? I create a new file and I put it in my project ? How I excute it and how I can see the reason of the error in my function ? Or I put this file in the function when I have the error like the solution proposed by #Lawrence Cherone ?
This solution it seems worked fine and the problem is resolved.
This following is my small code of my function, can you guide me how I create this logfile to debug it:
public function parseEquipment($filePath = null) {
set_time_limit(0);
$listEquipement = [];
$count = 0;
$chunkSize = 1024;
$objReader = PHPExcel_IOFactory::createReader(PHPExcel_IOFactory::identify($filePath));
$spreadsheetInfo = $objReader->listWorksheetInfo($filePath);
$chunkFilter = new \Floose\Parse\ChunkReadFilter();
$objReader->setReadFilter($chunkFilter);
$objReader->setReadDataOnly(true);
$chunkFilter->setRows(0, 1);
$objPHPExcel = $objReader->load($filePath);
$totalRows = $spreadsheetInfo[0]['totalRows'];
for ($startRow = 1; $startRow <= $totalRows; $startRow += $chunkSize) {
$chunkFilter->setRows($startRow, $chunkSize);
$objPHPExcel = $objReader->load($filePath);
$sheetData = $objPHPExcel->getActiveSheet()->toArray(null, null, true, false);
$startIndex = ($startRow == 1) ? $startRow : $startRow - 1;
if (!empty($sheetData) && $startRow < $totalRows) {
$dataToAnalyse = array_slice($sheetData, $startIndex, $chunkSize);
//echo 'test1';
if($dataToAnalyse[1][0]==NULL){
//echo 'test2';
break;
}
//echo 'test3';
//var_dump($sheetData);
for ($i = 0; $i < $chunkSize; $i++) {
if ($dataToAnalyse[$i]['0'] != NULL) {
//echo 'OK';
$listEquipement[] = new Article($dataToAnalyse[$i]['3'], $dataToAnalyse[$i]['4'], $dataToAnalyse[$i]['2']);
// echo 'test4';
$count++;
}
}
}
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel, $sheetData);
}
//var_dump(array_slice($sheetData, $startIndex, $chunkSize););
return $listEquipement;
}
error_log("You messed up!".$my_message, 3, "/var/tmp/custom-errors.log");
I want to write a code to remove extra delimiters for each row for a .csv file. With another code i have already determined that the .csv file only contains rows with too many delmiters. I further know which column (after nth delimiter) has extra delimiters. I have already written most of the code, but it's not working yet. Help is very much appreciated.
My PHP skills are still basic.
<?php
$delimiter = ';'; //type delimiter
$delimiter_start_column =23; //column-to-be-cleaned starts after this delimiter
$exp_delimiter =63; //expected delimiters per row
$total_delimiter =substr_count($line,$delimiter); //total delimiters in row
$delimiter_end_column =($exp_delimiter - $delimiter_start_column) + ($total_delimiter - $exp_delimiter); //column-to-be-cleaned ends before this delimiter
function splitleft($line,$delimiter,$delimiter_start_column){
$max = strlen($line);
$n = 0;
for($i=0;$i<$max;$i++){
if($line[$i]==$delimiter){
$n++;
if($n>=$delimiter_start_column){
break;
}
}
}
$arr[] = substr($line,0,$i);
return $arr;
}
function splitright($line,$delimiter,$delimiter_end_column){
$max = strlen($line);
$n = 0;
for($i=0;$i<$max;$i++){
if($line[$i]==$delimiter){
$n++;
if($n>=$delimiter_end_column){
break;
}
}
}
$arr[] = substr($line,$i,$max);
return $arr;
}
// determine start time in microseconds for runtime calculation
$file['datestamp'] = date("Y-m-d_H-i-s", $start);
$input['folder'] = 'input\\';
$input['file'] = ''; //enter filename
$output['folder'] = 'output\\';
$output['file_cleaned'] = $file['datestamp'].'_cleaned_';
// open input file read-only
$handle['input'] = #fopen($input['folder'].$input['file'], "r");
// initialize line, clean and dirty counters
$counter['total'] = 0;
$counter['cleaned'] = 0;
if($handle['input']) {
// open output files. set point to end of file.
$handle['cleaned'] = #fopen($output['folder'].$output['file_cleaned'].$input['file'], "a");
while(($line = fgets($handle['input'])) !== false) {
// increment line counter
$counter['total']++;
$result = substr_count($line, $delimiter);
if($result == $exp_delimiters AND $counter['line'] != 1 AND $line != $header) {
// if the number of delimiters matches the expected number as represented by $exp_delimiters
// increment clean lines counter
$counter['cleaned']++;
$output_file = $handle['cleaned'];
}
else {
// else, if the number of delimiters does not match the expectation
// remove extra delmiters from column
$line_cleaned = splitleft + str_replace(";","",substr($line,strlen(splitleft()),(strlen($line)-strlen(splitleft())-strlen(splitright()))) + splitright());
$output_file = $handle['cleaned'];
}
// prefix line number
$line = $counter['total'].$delimiter.$line;
// write line to correct output file
fwrite($output_file, $line_cleaned);
// output progress every 20.000 processed lines
if($counter['total'] % 20000 == 0) {
echo number_format($counter['total'], 0, ',', '.')."\r\n";
}
}
if(!feof($handle['input'])){
echo "Error: unexpected fgets() fail\n";
}
// close all input and output files
foreach($handle AS $close) {
fclose($close);
}
}
?>
Using Magento with Zend_Pdf and a couple of custom classes that allow for the printing/downloading of PDFs with certain header/table specifications. The problem is that it cuts off after the first page and doesn't create a new page when the items list is more than about 20 items.
This code:
public function getOutput()
{
$this->pages[] = $this->page;
return $this->render();
}
And this code:
$pdf = new PrintPdf();
$pdf->generate($sourceData);
$output = $pdf->getOutput();
echo $output;
Are where I believe the error is happening in. If I change the "return" in the first code to "echo" it will output the correct data to the browser, but when I then try and pass it through the second code, it only puts out one page of data.
Any advice would be appreciated as I have been working on this for about 2 weeks.
UPDATE:
I was told this piece of code:
private function drawLineItems($tableData)
{
$this->drawHeading($this->__('Line Items'));
// Draw table
$this->decOffset(35);
$this->colorLine(cBLUE);
$this->page->setLineWidth(0.5);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
$this->fontSize(FONT_SMALL);
$this->colorFill(cBLUE);
$this->decOffset(15);
$sum = ($this->pMargin + 10);
for($idx = 0; $idx < sizeof($tableData['heading']); $idx++) {
$pos = $sum;
$this->page->drawText($tableData['heading'][$idx], $sum, $this->yOffset);
$sum += ($tableData['width'][$idx] + 10);
$tableData['width'][$idx] = $pos;
}
$this->decOffset(10);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
$this->fontSize(8);
$this->colorFill(cLIGHT);
$this->colorLine(cBORDER);
foreach($tableData['rows'] as $row) {
$this->decOffset(15);
$yOffset = $this->yOffset;
for($idx = 0; $idx < sizeof($row); $idx++) {
if ($tableData['heading'][$idx] == 'Description') {
$lines = $this->_breakTextToLines($row[$idx], $tableData['width'][$idx + 1] - $tableData['width'][$idx]);
foreach ($lines as $line) {
$this->page->drawText($line, $tableData['width'][$idx], $yOffset);
$yOffset -= 10;
}
} else {
$this->page->drawText($row[$idx], $tableData['width'][$idx], $this->yOffset);
}
}
$this->decOffset($this->yOffset - $yOffset);
$this->page->drawLine($this->pMargin, $this->yOffset, $this->pWidth - $this->pMargin, $this->yOffset);
}
$this->decOffset(20);
$this->fontSize(FONT_NORMAL);
$this->colorFill(cDARK);
$this->page->drawText($this->__('Grand Total') . ': ' . $tableData['total'], $this->pWidth - 125, $this->yOffset);
}
is probably where the problem is as it doesn't form a new page after a certain number of items. My problem now lies in accomplishing this task. Help would still be appreciated.
I found that adding this code:
if( $this->yOffset < 25){
$this->yOffset = $this->pHeight - 25;
$yOffset = $this->yOffset;
$this->pages[] = $this->page;
$this->page = $this->newPage(Zend_Pdf_Page::SIZE_A4);
$this->fontSize(8);
$this->colorFill(cLIGHT);
$this->colorLine(cBORDER);
}
after
$yOffest = $this->yOffset
in the third part of the code in the question, fixed the problem!
Similar to: How to read only 5 last line of the text file in PHP?
I have a large log file and I want to be able to show 100 lines from position X in the file.
I need to use fseek rather than file() because the log file is too large.
I have a similar function but it will only read from the end of the file. How can it be modified so that a start position can be specified as well? I would also need to start at the end of the file.
function read_line($filename, $lines, $revers = false)
{
$offset = -1;
$i = 0;
$fp = #fopen($filename, "r");
while( $lines && fseek($fp, $offset, SEEK_END) >= 0 ) {
$c = fgetc($fp);
if($c == "\n" || $c == "\r"){
$lines--;
if($revers){
$read[$i] = strrev($read[$i]);
$i++;
}
}
if($revers) $read[$i] .= $c;
else $read .= $c;
$offset--;
}
fclose ($fp);
if($revers){
if($read[$i] == "\n" || $read[$i] == "\r")
array_pop($read);
else $read[$i] = strrev($read[$i]);
return implode('',$read);
}
return strrev(rtrim($read,"\n\r"));
}
What I'm trying to do is create a web based log viewer that will start from the end of the file and display 100 lines, and when pressing the "Next" button, the next 100 lines preceding it will be shown.
If you're on Unix, you can utilize the sed tool. For example: to get line 10-20 from a file:
sed -n 10,20p errors.log
And you can do this in your script:
<?php
$page = 1;
$limit = 100;
$off = ($page * $limit) - ($limit - 1);
exec("sed -n $off,".($limit+$off-1)."p errors.log", $out);
print_r($out);
The lines are available in $out array.
This uses fseek to read 100 lines of a file starting from a specified offset. If the offset is greater than the number of lines in the log, the first 100 lines are read.
In your application, you could pass the current offset through the query string for prev and next and base the next offset on that. You could also store and pass the current file position for more efficiency.
<?php
$GLOBALS["interval"] = 100;
read_log();
function read_log()
{
$fp = fopen("log", "r");
$offset = determine_offset();
$interval = $GLOBALS["interval"];
if (seek_to_offset($fp, $offset) != -1)
{
show_next_button($offset, $interval);
}
$lines = array();
for ($ii = 0; $ii < $interval; $ii++)
{
$lines[] = trim(fgets($fp));
}
echo "<pre>";
print_r(array_reverse($lines));
}
// Get the offset from the query string or default to the interval
function determine_offset()
{
$interval = $GLOBALS["interval"];
if (isset($_GET["offset"]))
{
return intval($_GET["offset"]) + $interval;
}
return $interval;
}
function show_next_button($offset, $interval)
{
$next_offset = $offset + $interval;
echo "Next";
}
// Seek to the end of the file, then seek backward $offset lines
function seek_to_offset($fp, $offset)
{
fseek($fp, 0, SEEK_END);
for ($ii = 0; $ii < $offset; $ii++)
{
if (seek_to_previous_line($fp) == -1)
{
rewind($fp);
return -1;
}
}
}
// Seek backward by char until line break
function seek_to_previous_line($fp)
{
fseek($fp, -2, SEEK_CUR);
while (fgetc($fp) != "\n")
{
if (fseek($fp, -2, SEEK_CUR) == -1)
{
return -1;
}
}
}
Is "position X" measured in lines or bytes? If lines, you can easily use SplFileObject to seek to a certain line and then read 100 lines:
$file = new SplFileObject('log.txt');
$file->seek(199); // go to line 200
for($i = 0; $i < 100 and $file->valid(); $i++, $file->next())
{
echo $file->current();
}
If position X is measured in bytes, isn't it a simple matter of changing your initial $offset = -1 to a different value?
I would do it as followed:
function readFileFunc($tempFile){
if(#!file_exists($tempFile)){
return FALSE;
}else{
return file($tempFile);
}
}
$textArray = readFileFunc('./data/yourTextfile.txt');
$slicePos = count($textArray)-101;
if($slicePos < 0){
$slicePos = 0;
}
$last100 = array_slice($textArray, $slicePos);
$last100 = implode('<br />', $last100);
echo $last100;