How can you determine remaining space on page with ezpdf? - php

I'm using rospdf/php-pdf - the middle of the pdf is a table of variable length. I want to make sure there is enough space to print the final section on the page, if not I want to add a new page. I'd like to do something like this but $position has no value. How can I find out the current position?
$position = $pdf->ezSetDy;
if($position < 100){
$pdf->ezNewPage();
}

You can try the following:
$yPos = $pdf->y - $pdf->ez['bottomMargin'];
if ($yPos < 100) {
$pdf->ezNewPage();
}

Related

PHP Regex statements

With a post request, I'm trying to return a booking number to my iOS App. It posts the current date as a string which is written to a file on my server.
The logic is, that whenever the date from the last entry does not match the date passed in the post request, the booking number starts from 01. If it is the same date, the booking number gets increased by one.
The text file I write my entries to looks like this:
2017-03-03, 1;
2017-03-03, 2;
2017-03-03, 3;
2017-03-03, 4;
2017-03-03, 5
I am using regex to find the last entry, comparing its date to the current and assigning the new booking number.
Here is my code:
if (preg_match_all("/\d{4}-\d{1,2}-\d{1,2},\s\d\z/", $textFileString, $entryArray)) {
if (preg_match_all("/\d{4}-\d{1,2}-\d{1,2}/", $entryArray[0][0], $dateArray)) {
if ($dateArray[0][0] == $currentDate) { //$currentDate's value comes from the post request
if (preg_match_all("/\d\z/", $entry[0][0], $numberArray)) {
$bookingNumber = $output_array[0][0]+1;
}
} else {
$bookingNumber = 1;
}
}
}
Note: I do successfully write to the file.
I suggest switching to preg_match (since you only need to find a single match) and add capturing groups to the pattern so as to reduce the code a bit:
$textFileString = '2017-03-03, 1;
2017-03-03, 2;
2017-03-03, 3;
2017-03-03, 4;
2017-03-03, 5';
$currentDate = '2017-03-03';
if (preg_match("/(\d{4}-\d{1,2}-\d{1,2}),\s(\d{1,2})\z/", $textFileString, $entryArray)) {
if ($entryArray[1] == $currentDate) { //$currentDate's value comes from the post request
$bookingNumber = $entryArray[2]+1;
} else {
$bookingNumber = 1;
}
}
echo $bookingNumber;
See the PHP demo.
Note you may also replace \z with $ since the $ anchor matches at the end of the string (or before a final LF in the string) by default.
Now, (\d{4}-\d{1,2}-\d{1,2}),\s(\d{1,2})\z contains two capturing groups that you may access via $entryArray[1] and $entryArray[2].

FPDF - Determining height of MultiCell before placing?

The basic question: Is it possible to determine the height of a MultiCell before placing it in the document?
The reason: I've been tasked with creating a PDF version of a form. This form allows text input, with a resulting variable length. One person my not enter anything, another person may write a few paragraphs. "The Powers That Be" do not want this text breaking between pages.
Currently, after placing each block, I check the position on the page, and if I'm near the end, I create a new page.
if($this->getY() >= 250) {
$this->AddPage('P');
}
For the most part, this works. But there are the few sneaky ones that come in at, say 249, and then have boatloads of text. It seems it would make more sense to determine the height of a block before placing it to see if it actually fits on the page.
Surely there must be a way to do this, but Googling around hasn't proven very helpful.
Edit to clarify: The PDF is being generated after the form is submitted. Not an active, editable PDF form...
Earned the tumbleweed badge for this question. :( Anyway, in the off chance someone has the same issue, I figured I'd answer with what I did. I doubt this is the most efficient method, but it got the job done.
First, I create two FPDF objects; a temporary one that never gets output and the final, complete pdf that the end user will see.
I get my current Y coordinate in both objects. I then place the block of data using Cell() or MultiCell() (for this form, usually a combination of the two) into the temporary object, and then check the new Y coordinate. I can then do the math to determine the height of the block. -Note, the math can get a bit funky if the block breaks across pages. Remember to take your top and bottom margins into account.
Now that I know the height of a block, I can take the current Y coordinate of the destination object, subtract it from the total height of a page(minus bottom margin) to get my available space. If the block fits, place it, if not, add a page and place it at the top.
Repeat with each block.
Only caveat I see is if any single block is longer then an entire page, but with this form, that never happens. (famous last words...)
See also https://gist.github.com/johnballantyne/4089627
function GetMultiCellHeight($w, $h, $txt, $border=null, $align='J') {
// Calculate MultiCell with automatic or explicit line breaks height
// $border is un-used, but I kept it in the parameters to keep the call
// to this function consistent with MultiCell()
$cw = &$this->CurrentFont['cw'];
if($w==0)
$w = $this->w-$this->rMargin-$this->x;
$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
$s = str_replace("\r",'',$txt);
$nb = strlen($s);
if($nb>0 && $s[$nb-1]=="\n")
$nb--;
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$ns = 0;
$height = 0;
while($i<$nb)
{
// Get next character
$c = $s[$i];
if($c=="\n")
{
// Explicit line break
if($this->ws>0)
{
$this->ws = 0;
$this->_out('0 Tw');
}
//Increase Height
$height += $h;
$i++;
$sep = -1;
$j = $i;
$l = 0;
$ns = 0;
continue;
}
if($c==' ')
{
$sep = $i;
$ls = $l;
$ns++;
}
$l += $cw[$c];
if($l>$wmax)
{
// Automatic line break
if($sep==-1)
{
if($i==$j)
$i++;
if($this->ws>0)
{
$this->ws = 0;
$this->_out('0 Tw');
}
//Increase Height
$height += $h;
}
else
{
if($align=='J')
{
$this->ws = ($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
$this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
}
//Increase Height
$height += $h;
$i = $sep+1;
}
$sep = -1;
$j = $i;
$l = 0;
$ns = 0;
}
else
$i++;
}
// Last chunk
if($this->ws>0)
{
$this->ws = 0;
$this->_out('0 Tw');
}
//Increase Height
$height += $h;
return $height;
}
In addition to JLuc answer which is working as one would imagine it, too. Implementing this functionality however is not trivial and requires you to extend the main fpdf class.
First off if you have an extended fpdf already you could just copy JLuc's answer and skip this step. If not, go ahead like this:
create a File and Class that extends FPDF (name the file as your class name):
<?php
namespace YourNameSpace\Library;
class FpdfExtended extends \FPDF {
...
}
If you are not using namespaces you could just use require. Once that file is created insert the GetMultiCellHeight from the gist or this answer.
Now you'd need to instantiate the extended Class a simple constructor most likely suffices.
use YourNameSpace\Library\FpdfExtended
...
$pdf = new FpdfExtended();
...
now you could simply use the GetMultiCellHeight method to decide the next cells height like so:
$col1 = 'col 1 text without line break';
$col2 = 'col 2 text with line break \n and some more text';
// get next cell height
$nextHeight = $pdf->GetMultiCellHeight($width, $height, $col2);
$pdf->MultiCell($width, $nextHeight, $col1, 0, 'L', 1);
Good luck and happy coding you poor souls still using FPDF.
I have done it by this way. We are passing height in multicell. That is $h. Total height would be (number of lines * $h). Because $h is height of one line. And we want to know total height so total height is $totalLines * $h.

Insert random letters and letters of string in a table just like in wordsearch

this codes is for displaying random letters with a table like in a word search game. The problem is,.I can't insert strings in the table,. what if I have array of strings,. eg., sample, them, power, some. How can I insert these strings in the cell?
I am creating something like this http://children.pfcblogs.com/learn/word-search-test/
$row = 10;
$col = 10;
$w = 8;
$h = 8;
for ($r=1;$r<=$row;$r++) {
for ($c=1;$c<=$col;$c++) {
$pdf->Cell($w,$h,$str= array_merge(range('A','Z'))[mt_rand(1,24)],1,0,'C');
}
$pdf->Ln($h);
}
This is way above and beyond for stackoverflow, but I'm in a good mood. :-)
So this takes a string of words (you can add more) separated by comas and splits those in to an array and then finds words that will fit until it gets down to 1 letter then it just uses the random letters from before to fill the space.
This is far from perfect one thing you'd see is all of the lines will start with words and end with random letters. Also, the words are only horizontal not vertical. Building matrixes of words horizontal, vertical, and diagonal gets pretty complex and is certainly beyond the scope of this site.
Here is the code as it stands. It's a good start.
$row = 10;
$col = 10;
$w = 8;
$h = 8;
$characters = range('A','Z');
$words="in, on, it, up, at, am, of, and, band, banned, bland, brand, brande, canned, chand, fanned, gland, grand, grande, hand, land, lande, mande, manned, panned, planned, rand, sande, scanned, shand, spanned, stand, strand, strande, tanned, vande, zand";
$wordList = explode(",",$words);
$myWord="";
$max = count($characters) - 1;
for ($r=1;$r<=$row;$r++) {
for ($c=1;$c<=$col;$c++) {
//if we have more than 1 space
//(enough room for a 2 or more letter word)
$maxWordLength=$col-$c+1;
if($maxWordLength > 1){
//get a word if we need a new one
if(empty($myWord)){
$wordLen=99;
while($wordLen > $maxWordLength){
$myWord=trim(strToUpper($wordList[mt_rand(0,count($wordList))]));
$wordLen=strlen($myWord);
}
}
//get the next letter of the word we're using
$thisChar=substr($myWord,0,1);
$myWord=substr($myWord,1);
}else{
//if we don't have room for a word put a random letter
$thisChar=$characters[mt_rand(0,$max)];
}
$pdf->Cell($w,$h,$thisChar,1,0,'C');
//for debugging (remove this)
echo($thisChar.' ');
}
$pdf->Ln($h);
//for debugging remove this
echo('<hr>');
}
Also, here is a link to an existing open source PHP solution that is along the lines of what you're looking for. I downloaded it and took a peek and it's about 3000 lines of code. So as I said well beyond the scope of stack overflow.
http://fswordfinder.sourceforge.net/
Try this code...
$row = 10;
$col = 10;
$w = 8;
$h = 8;
$characters = range('A','Z');
$max = count($characters) - 1;
for ($r=1;$r<=$row;$r++) {
for ($c=1;$c<=$col;$c++) {
$pdf->Cell($w,$h,$characters[mt_rand(0,$max)],1,0,'C');
//for debugging (remove this)
echo("$w,$h,{$characters[mt_rand(0,$max)]},1,0,'C'");
echo('<br>');
}
$pdf->Ln($h);
}
I added in the echo code to see what it's doing since I don't have the PDF library that you are using so I couldn't test that but the echo output was like this so assuming the pdf cell method is set up correctly it should work.
8,8,D,1,0,'C'
8,8,S,1,0,'C'
8,8,C,1,0,'C'
8,8,C,1,0,'C'
8,8,F,1,0,'C'
8,8,Q,1,0,'C'
8,8,B,1,0,'C'
8,8,H,1,0,'C'
8,8,C,1,0,'C'
8,8,N,1,0,'C'
8,8,A,1,0,'C'
8,8,H,1,0,'C'
8,8,Y,1,0,'C'
8,8,T,1,0,'C'
8,8,B,1,0,'C'
8,8,V,1,0,'C'
8,8,Y,1,0,'C'
...

Automatically creating next and previous type pages using glob

Trying to make it so that the glob function displays only the first 10 results (text files from a folder) and then automatically the next 10 with a next button.
Currently, I used array_slice to display only the first 10, but I'm not sure how to automate the process.
foreach(array_slice(glob("*.txt"),0,9) as $filename) {
include($filename); }
Oh and while I'm at it, if possible, display something like "displaying 1-10" and last/first links. I could probably figure that out myself after I get past the first obstacle, so don't bother with this unless it's a super easy solution.
What you're trying to accomplish is called pagination. From your example, you can dynamically choose which ten you're viewing by setting a variable that determines what number (file) to start at.
Example:
<?php
$start = isset( $_GET['start']) ? intval( $_GET['start']) : 0;
$glob_result = glob("*.txt");
$num_results = count( $glob_result);
// Check to make sure the $start value makes sense
if( $start > $num_results)
{
$start = 0;
}
foreach( array_slice( $glob_result, $start, 9) as $filename)
{
include( $filename); // Warning!
}
If you only want to do increments of 10, you can add a check to make sure $start is divisible by 10, something like this after $start is retrieved from the $_GET array:
$start = ( $start % 10 == 0) ? $start : 0;
Now, for links, all you need to do is output <a> tags that have the start parameter set correctly. You will have to do some logic to calculate the next and previous values correctly, but here is a simple example:
$new_start = $start + 10;
echo 'Next';
Edit: As the comments above suggest, you probably do not want to include() these files, as include() will attempt to interpret these files as PHP scripts. If you just need to get the contents of the text files, use file_get_contents instead.

Change the value of variable PHP

I have input fields, which I process with AJAX and send it on another file.
The value of the inputs is always different.
How in the file, where I get the data from AJAX, to change the variable id always when I get the data from AJAX.
Example:
I get the data from AJAX in this file:
<?php
$id=1;
echo '<div id="$id"></div>';
?>
Then I display the result in the page with AJAX.
I want the id of the div to be always different.
if you want $id a random number use the function randlink text
$id=rand(0,100); // random between 0 and 100, 0 and 100 incluse
you can also create a random string
function genRandomString($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$string = '';
for ($p = 0; $p < $length; $p++) {
$string .= $characters[rand(0, strlen($characters))];
}
return $string;
}
One can create different random number through time checking, this will create random number on the basis of time and will generate different number each microseconds.
//this will add a char on the beginning of the value so it do not start with numeral
$str=range(a,z);
//using date function for generating random number
$i= $str[rand(0,25)].date('Ymzhisu');

Categories