create separate pdf files in yii - php

I am trying to create 2 separate pdf files with different content. I have the following code which creates the 2 files.
$invoice = Invoices::model()->findByPk($_GET['id']);
$invoicedetail = InvoicesDetail::model()->findAll(array("condition"=>"invoiceno=".$invoice->INVOICENO . " && biditems_id is null"));
$client = $invoice->pROJ->oRDERNO->addressesinvoices;
$invoices = Invoices::model()->findAll(array("condition"=>"PROJID=".$invoice->PROJID . " && INVOICENO != ".$invoice->INVOICENO));
/*$this->renderPartial("partialInvoice",
array(
"invoice"=>$invoice,
"client"=>$client,
//"lookupprocesstotalArr"=>$lookupprocesstotalArr,
"adjustments"=>$invoices,
"invoicedetail"=>$invoicedetail[0]
),true);
*/
$html = $this->renderPartial("partialInvoice",
array(
"invoice"=>$invoice,
"client"=>$client,
//"lookupprocesstotalArr"=>$lookupprocesstotalArr,
"adjustments"=>$invoices,
"invoicedetail"=>$invoicedetail[0]),true);
$filename_invoice = 'invoice_'.$invoice->INVOICENO.'.pdf';
Yii::import('application.extensions.pdfable.WkHtmlToPdf');
$pdf = new WkHtmlToPdf(array(
'no-outline', // Make Chrome not complain
'margin-top' => 10,
'margin-right' => 10,
'margin-bottom' => 10,
'margin-left' => 10,
));
$pdf->setOptions(array(
'orientation' => 'portrait'
));
// Add a HTML file, a HTML string or a page from a URL
$pdf->addPage($html);
// Save the PDF
$pdf->saveAs("/tmp/$filename_invoice");
// ... or send to client as file download
/*if(!$pdf->send($filename)){
throw new Exception('Could not create PDF: '.$pdf->getError());
}*/
$globalController = new GlobalController;
//$project = Projects::model()->findAll(array("condition"=>"PROJID=".$_GET['PROJID']));
//$projid = $_GET['PROJID'];
$pdfDetail = new WkHtmlToPdf();
$orientation = "Landscape";
$pdfDetail->setOptions(array('orientation'=>$orientation,
'no-outline', // Make Chrome not complain
'margin-right' => 10,
'margin-bottom' => 5,
'margin-left' => 10,
));
//$this->layout = 'pdf';
//get list of process stages for this project
$lastrun = $globalController->lastRun($invoice->PROJID);
$processstages = ExtHtml::listData($lastrun, 'ID',array('cumulative','ITEM'));
$lookupprocesstotalArr = $globalController->lookupprocesstotal($invoice->PROJID,$processstages);
// get all lines
$connection = Yii::app()->db;
$sql = "SELECT jobs.JOBNO, jobs.NAME, FSP, LSP, SHOTS, KM
FROM hdb.jobs
join detailsseismic on jobs.JOBNO = detailsseismic.JOBNO
where jobs.PROJID = :pid";
$command=$connection->createCommand($sql);
$command->bindValue(":pid",$invoice->PROJID,PDO::PARAM_INT);
$command->execute();
$lines = $command->queryAll();
$dates = array();
foreach ($lines as $arr) {
$sql = "SELECT jobsprocesscomplete.datedone, ITEM_fk
FROM hdb.jobsprocesscomplete
left join lookupprocess on jobsprocesscomplete.lookupprocess_id = lookupprocess.ID
left join biditems on lookupprocess.biditems_id = biditems.ITEMID
where jobno = :jobno";
$command=$connection->createCommand($sql);
$command->bindValue(":jobno",$arr['JOBNO'],PDO::PARAM_INT);
$command->execute();
$dates[$arr['JOBNO']] = $command->queryAll();
}
/*echo $this->renderPartial('pdf_'.$_GET['type'],array(
'lookupprocesstotalArr'=>$lookupprocesstotalArr,
"currency"=>$project[0]->currency0->currency,
"projectpercent"=>$project[0]->PERCENT,
"name"=>$project[0]->PROJECT . " - " . $project[0]->oRDERNO->cONTACTsugar->first_name . " " . $project[0]->oRDERNO->cONTACTsugar->last_name,
"lines"=>$lines,
"dates"=>$dates,
"project"=>$project[0]));
*/
$detail = $this->renderPartial('/lookupprocess/pdf_detail',array(
'lookupprocesstotalArr'=>$lookupprocesstotalArr,
"currency"=>$invoice->pROJ->currency0->currency,
"projectpercent"=>$invoice->pROJ->PERCENT,
"name"=>$invoice->pROJ->PROJECT . " - " . $invoice->pROJ->oRDERNO->cONTACTsugar->first_name . " " . $invoice->pROJ->oRDERNO->cONTACTsugar->last_name,
"lines"=>$lines,
"dates"=>$dates,
"project"=>$invoice->pROJ
),true);
$filename_detail = $invoice->PROJID . "_" . date("ymd-his") . ".pdf";
// Add a HTML file, a HTML string or a page from a URL
$pdfDetail->addPage($detail);
// Save the PDF
$pdfDetail->saveAs("/tmp/$filename_detail");
shell_exec("gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=/tmp/$filename_invoice /tmp/$filename_invoice /tmp/$filename_detail");
echo "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=/tmp/$filename_invoice /tmp/$filename_invoice /tmp/$filename_detail";
exit();
/*
// ... or send to client as file download
if(!$pdf->send($filename_invoice)){
throw new Exception('Could not create PDF: '.$pdf->getError());
}
The problem i have is the 1st pdf that gets created is overwritten by the content of the 2nd pdf which makes no sense.

I do not know the class you are using but this code seems suspicios:
-sOutputFile=/tmp/$filename_invoice /tmp/$filename_invoice /tmp/$filename_detail
For me it seems that you convert 2 files into 1 output files, so logically you overwrite it!?

Related

PhpSpreadsheet charts not saving and/or corrupting file

So I'm working on a reporting application that requires generating Xls files with charts. The charts don't appear to be working though. I've tried just replacing the code below with the example in the PhpSpreadsheet github, but that also doesn't work.
I have the following for inserting the data (and chart) into the worksheet:
$this->spreadsheet->createSheet();
$worksheet = $this->spreadsheet->getActiveSheet();
$worksheet->setTitle($title);
$periodStartArray = array(array('', $periodStartDate, $periodEndDate));
while (!empty($stack)) {
$node = array_pop($stack);
if ($node->getData()['portfolioData'][0] != null) {
if ($node->getData()['portfolioData'][0]->getIncludeInStatusSide()) {
$startValue = (float)$this->getDataPoint($node, 'general', $this->periodStart, 'value');
$startValuePercent = number_format(($startValue / $this->startingTotalValues) * 100, $this->percentDecimals, $decimalPoints, $separators);
$endValue = (float)$this->getDataPoint($node, 'general', $this->periodEnd, 'value');
$endValuePercent = number_format(($endValue / $this->endingTotalValues) * 100, $this->percentDecimals, $decimalPoints, $separators);
$startArray = array($node->getData()['portfolioData'][0]->getNavn(), $startValuePercent, $endValuePercent);
$periodStartArray[] = $startArray;
}
}
}
$maxSize = count($periodStartArray);
$worksheet->fromArray($periodStartArray);
//$title . '!$B$1'
$dataSeriesLabels1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $title . '!$B$1', null, 1),
];
// $maxSize - 1 should give the actual number of data points (since the first entry in the array is the
// date row
$dataString = "'" . $title . "'" . '!$A$2:$A$' . $maxSize;
$xAxisTickValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $dataString, null, $maxSize - 1)
];
$dataString = "'" . $title . "'" . '!$B$2:$B$' . $maxSize;
$dataSeriesValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $dataString, null, $maxSize - 1)
];
$series = new DataSeries(
DataSeries::TYPE_PIECHART,
null,
range(0, count($dataSeriesValues1) - 1),
$dataSeriesLabels1,
$xAxisTickValues1,
$dataSeriesValues1
);
$layout = new Layout();
$layout->setShowVal(true);
$layout->setShowPercent(false);
$plotArea = new PlotArea($layout, array($series));
$legend = new Legend(Legend::POSITION_RIGHT, null, false);
$title = new Title($title);
$chart1 = new Chart(
'chart1',
$title,
$legend,
$plotArea,
true,
0,
null,
null
);
$chart1->setTopLeftPosition('A10');
$chart1->setBottomRightPosition('P25');
$worksheet->addChart($chart1);
It successfully inserts the data into the spreadsheet, but does not print out any charts. Here is where I'm saving the spreadsheet:
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xls($this->spreadsheet);
$writer->setIncludeCharts(true);
$writer->save($this->outputFile);
So I'm including the charts, but no charts appear. When I change the format to Xlsx, it seems to at least try to insert the charts but they're corrupt and Excel removes them. It's just simple data. Literally one row of a company name in the A column and two dates of values down the B and C columns. When I manually insert the charts after the excel file gets generated it works no problem.
use this
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
instaea of 0
like in sample file
https://github.com/PHPOffice/PhpSpreadsheet/blob/master/samples/templates/chartSpreadsheet.php
Change the 0 to 'gap' when creating the chart.
$chart1 = new Chart(
'chart1',
$title,
$legend,
$plotArea,
true,
'gap', // use 'gap' instead of 0,
null,
null
);
Below is the issue for PhPSpreadsheet
File containing a chart can not be opened by Excel 2003/2013/2019

When i generate excel sheet using php code it shows some error , when open in microsoft excel

When I generate an excel sheet from the database it shows an error that "excel file does not match format. Do you want to open it anyway?" and it says to click on ok button to upgrade format of excel file. When I click on ok it works fine... but in mobile its not open.
i want to generate microsoft excel file with no error.
//generating Excel File
$setSql = "SELECT * from demo table";
$setRec = mysqli_query($db, $setSql);
$header_name="DATA LIST IN EXCEL";
$Event= "This is a demo";
date_default_timezone_set("Asia/Kolkata");
$date='Export Date:-'.date("l, jS \of F Y h:i:s A");
$columnHeader = '';
$columnHeader = "Name" . "\t" . "Date" . "\t". "Mode No" . "\t". "Address" . "\t". "eduction"."\t"."Organisation" . "\t". "Paid Status" . "\t";
$setData = '';
while ($rec = mysqli_fetch_row($setRec)) {
$rowData = '';
foreach ($rec as $value) {
$value = '"' . $value . '"' . "\t";
$rowData .= $value;
}
$setData .= trim($rowData) . "\n";
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename= file_name.xls");
header("Pragma: no-cache");
header("Expires: 0");
echo $header_name ."\t\t\t\t\t\t\t\n". $Event ."\t\t\t". $date ."\n". ucwords($columnHeader) . "\n" . $setData . "\n";
Here you have our code.
Notice
ob_clean before download
This is the tricky point. If you have some content in the output buffer (maybe for an incorrect include file) it is sent with the file. So, you have to clean it before any download command
Added BOM header to CSV file
And, if you plan to open the file with Excel, and the file is UTF8, you have to add BOM header
public function reportAsset($budgetPeriod_id)
{
$timeProcess = round(microtime(true) / 1000);
if ($budgetPeriod_id) {
$budget = \App\Models\Invoicing\BudgetPeriod::select(['description'])->find((int) $budgetPeriod_id);
$client = \App\Models\Structure\Client::select(['description'])->find($this->client_id);
$filename = date('Ymd').'_'.$budget->description . '_' . $client->description . '.csv';
$headers = [
'Content-type' => 'text/csv;charset=UTF-8',
'Content-Disposition' => 'attachment; filename=' . $filename,
'Pragma' => 'no-cache',
'Expires' => '0',
];
$output = fopen($filename, "w");
// JMA: Add BOM header
fputs($output, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
fputcsv($output, [_i('Asset_id'), _i('Asset'), _i('Client Category'), _i('Budget'), _i('Spent'), _i('Available'),_i('Spent') .' %', _i('# Invoices')], ';');
$query = \App\Models\Invoicing\AssetBudget::query();
$query->has('asset')
->has('clientCategory')
->with('asset:PROCESS_ID,Identificador_Processo', 'clientCategory:id,description')
->orderBy('asset_id', 'clientCategory_id', 'clientCategory.id')
->selectRaw('amount as total, asset_id, budgetPeriod_id, clientCategory_id')
->where('budgetPeriod_id', $budgetPeriod_id)
->chunk($this::BUDGET_CHUNK, function ($chunk_query) use ($budgetPeriod_id, $output, $timeProcess) {
foreach ((array) $chunk_query as $report) {
foreach ($report as $rep) {
$row = [];
// JMA: The amount has to be the individual amount per asset
// So. we read asset_invoices where the invoice is in the budget period and category
// TODO: Replace this piece of code with consumedBudgetByRequest function in Invoicing BudgetController
// TODO: Try with calculateBudget but is not the same structure
//$invoices = \App\Library\Invoicing\BudgetCalculator::calculateBudget($rep->budgetPeriod_id, $rep->clientCategory_id, (array)$rep->asset_id);
$invoices=AssetInvoice::whereHas('invoice' , function ($invoice) use ($rep) {
$invoice->where('budgetPeriod_id',$rep->budgetPeriod_id)
->where('clientCategory_id',$rep->clientCategory_id);
}
)
->selectRaw('count(asset_id) as nInvoices, sum(amount) as spent')
->where('asset_id',$rep->asset_id)
->first();
// Log::debug('BudgetController->reportAsset: Invoices found='.$invoices->nInvoices.' spent='.$invoices->spent);
$row['asset_id'] = $rep->asset->PROCESS_ID;
$row['Identificador_Processo'] = $rep->asset->Identificador_Processo;
$row['clientCategory'] = $rep->clientCategory->description;
$row["budget"] = floatval($rep->total);
$row["spent"] = floatval($invoices->spent);
$row["available"] = $row["budget"] - $row["spent"];
if(floatval($rep->total)==0 ){
$row["percentaje"] = '';
}else{
$row["percentaje"] = number_format((float)(floatval($invoices->spent)*100)/ floatval($rep->total), 2, '.', '');
}
$row["nInvoices"] = floatval($invoices->nInvoices);
// Uncomment this line to monitor time consumption
// $row["times"] = $timeProcess - round(microtime(true) / 1000);
fputcsv($output, $row, ';');
}
}
});
fclose($output);
// CHECK THIS: Clean output buffer before sending files (avoid initial whitespaces)
if (ob_get_contents()) {
ob_clean();
}
// Send csv file as response
return response()->download($filename, $filename, $headers)->deleteFileAfterSend(true);
}

Running mqtt python script in PHP bluemix container

I am running a PHP code on docker container hosted in Bluemix. The PHP code calls a python script which is a MQTT based subscribe code. My idea was everytime the subscribed code gets MQTT message it will write the values to a text file. The PHP code will keep on checking every 10 seconds for new values in the file.
The VCAP_ENV variables are getting written correctly. However, the site does not load.
The python script executes successfully when i try it locally. So no errors there too.
My code is as follows:
PHP CODE:
<?php
if( getenv("VCAP_SERVICES") ) {
// get IoT service configuration from Bluemix
$services = getenv("VCAP_SERVICES");
$services_json = json_decode($services, true);
$mysql_config = $services_json["iotf-service"][0]["credentials"];
$org_id = $mysql_config["org"];
$port = $mysql_config["mqtt_u_port"];
$username = $mysql_config["apiKey"];
$password = $mysql_config["apiToken"];
}
// set configuration values
$config = array(
'org_id' => $org_id,
'port' => $port,
'app_id' => 'mymqttfinalservice',
'iotf_api_key' => $username,
'iotf_api_secret' => $password,
'device_id' => '007',
'qos' => 1
);
$file = fopen("VCAP_CONFIG.ini","w");
#fwrite($file,"[config]" . PHP_EOL );
#fwrite($file,"org =" . $org_id . PHP_EOL );
#fwrite($file,"apikey =" . $username . PHP_EOL );
#fwrite($file,"authkey =" . $password . PHP_EOL );
fwrite($file,"[config]" . "\n" );
fwrite($file,"org =" . $org_id . "\n" );
fwrite($file,"apikey =" . $username . "\n" );
fwrite($file,"authkey =" . $password . "\n" );
fclose($file);
$file = file_get_contents('VCAP_CONFIG.ini', true);
echo $file;
$command = 'chmod 777 /app/PythonSubscribeCode.py';
$output = '';
exec ( $command);
$command = 'python3 /app/PythonSubscribeCode.py 2>&1';
$output = exec ($command);
print_r($output);
$x = 1;
while($x == 1)
{
$config = parse_ini_file('Data.ini');
echo json_encode($config);
sleep(5);
}
?>
Python Script:
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
import os, json
import time
import configparser
# This is the Subscriber
settings = configparser.ConfigParser()
settings.read('VCAP_CONFIG.ini')
organization = settings['config']['org']
username = settings['config']['apikey']
password = settings['config']['authkey']
#Set the variables for connecting to the iot service
broker = ""
devicename = "007"
topic = "iot-2/type/DesktopApplication/id/007/evt/status/fmt/json"
#topic = 'iot-2/evt/status/fmt/json'
deviceType = "DesktopApplication"
clientID = "a:" + organization + ":appId"
print (clientID)
broker = organization + ".messaging.internetofthings.ibmcloud.com"
mqttc = mqtt.Client(clientID)
if username is not "":
mqttc.username_pw_set(username, password=password)
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
def on_subscribe(mosq, obj, mid, granted_qos):
print("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_message(mosq, obj, msg):
global message
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
def on_message(client, userdata, msg):
writeData = msg.payload.decode('utf-8')
parsed_json = json.loads(writeData)
UDD = parsed_json['UDD']
DDD = parsed_json['DDD']
PH = parsed_json['PH']
Ignition = parsed_json['Ignition']
# add the settings to the structure of the file, and lets write it out...
config = configparser.ConfigParser()
config['Data'] = {'UDD': UDD,
'DDD': DDD,
'PH': PH,
'Ignition':Ignition}
with open('Data.ini', 'w') as configfile:
config.write(configfile)
mqttc.connect(host=broker, port=1883, keepalive=60)
test = mqttc.subscribe(topic,0)
#print (test)
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.on_message = on_message
mqttc.loop_forever()
Can someone please guide on this?
Do you get any useful error messages from cf ic logs containerid to see what might be failing? As an alternate, you could also try execing into the container (either cf ic exec -ti containerid bash or docker exec...) and run the python script directly to see if that's giving you other errors when running there.

Database Query during Dynamic Drupal node creation to get Entity ID

I have a script which grabs the latest image from our surf webcam, it saves a node of type Photos. In that content type i have an entity field which references the swell size (content type swell_data). I can add a static entity id no problem:
// Reference Swell Data ID 176821
$node->field_buoy_ref[$node->language][0]['target_id'] = 176821;
How would I dynamically find the latest node created by the swell_data content type (added hourly using a CRON job) and use that value instead? For your reference this is the current script i am using (thanks to FooNinja)
define('DRUPAL_ROOT', getcwd());
require_once 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$bodytext = "This was the view from the Camera at ".date('gA')." on ".date('l F jS Y');
$node = new stdClass(); // Create a new node object
$node->type = "photos"; // Or page, or whatever content type you like
node_object_prepare($node);
$node->title = "Caswell Camera ". date('D M j G:i');
$node->language = LANGUAGE_NONE;
// Author
$node->name = "Gower Live"; // UID of the author of the node; or use $node->name
// Publish Node
$node->status = 1;
//Set Body Text
$node->body[$node->language][0]['value'] = $bodytext;
$node->body[$node->language][0]['summary'] = text_summary($bodytext);
$node->body[$node->language][0]['format'] = 'filtered_html';
//Set Image Location (Caswell)
$node->field_photo_location[$node->language][0]['lat'] = 51.570195982718374;
$node->field_photo_location[$node->language][0]['lng'] = -4.030849980797484;
// Set the Photos date
$node->field_image_date[$node->language][0]['value'] = date("Y-m-d H:i:s");
// From the Webcam
$node->field_webcam_photo[$node->language][0]['value'] = "Caswell";
// Reference Wave Buoy
$node->field_buoy_ref[$node->language][0]['target_id'] = 176821; // I'd this value dynamically pulled from the DB
// Attach Latest Webcam Image
$file_path = drupal_realpath('images/webcams/caswell-webcam.jpg');
$file = (object) array(
'uid' => 1,
'uri' => $file_path,
'filemime' => file_get_mimetype($file_path),
'status' => 1,
);
// You can specify a subdirectory, e.g. public://foo/
$file = file_copy($file, 'public://');
$node->field_user_photo[$node->language][0] = (array) $file;
$path = 'node_created_on' . date('YmdHis');
$node->path = array('alias' => $path);
if($node = node_submit($node)) { // Prepare node for saving
node_save($node);
echo "Node with nid " . $node->nid . " saved!\n";
}
thanks
Lee
I added the following below the Bootstrap Line and bingo.
$result = db_query("SELECT nid, title, created FROM {node} WHERE type = :type AND title =:title", array(
':type' => 'wavebuoy_data',
':title' => "Buoy ". date('D M j gA'),
));
foreach($result as $row) {
$wave_buoy_ref_value = $row->nid;
//print_r($row);
}
Then when building the node, added the following:
// Reference Wave Buoy
$node->field_buoy_ref[$node->language][0]['target_id'] = $wave_buoy_ref_value;
Lee

How to display tabs using Zend_PDF

I am having an issue with generating pdf documents. My tabulator characters are not displayed properly. I already tried different fonts, or encodings (UTF-8, Windows1552).
With some fonts the character is completely hidden. With some I get a square symbol displayed instead of my tab "\t".
Here is my code.
The question is "How to display tabs using Zend_PDF?"
public function generate()
{
$pdf = new Zend_Pdf();
$page = new Zend_Pdf_Page( Zend_Pdf_Page::SIZE_A4 );
//render basic template
$template = Zend_Pdf_Image::imageWithPath( APPLICATION_PATH . '/resources/pdf/template.png' );
$page->drawImage( $template, 0 ,0, 595, 842 );
//render document title
$font = Zend_Pdf_Font::fontWithPath( APPLICATION_PATH . '/resources/pdf/arial-bold.ttf' );
$page ->setFont($font, 14)
->drawText( 'Rechnung', 390, 700, 'utf-8' );
//render reciever adress
$font = Zend_Pdf_Font::fontWithPath( APPLICATION_PATH . '/resources/pdf/arial.ttf' );
$adressText = array(
'Kundennummer' . "\t" . $this->_user->getUserIdString(),
'Belegnummer' . "\t" . $this->_payin->getPayinIdString(),
'Datum' . "\t\t\t" . $this->_payin->getDateCreated()->format( 'd.m.Y' ),
'Seite' . "\t\t\t" . '1/1'
);
$page ->setFont($font, 12);
$adressY = 680;
foreach( $adressText as $line )
{
$page->drawText( $line, 390, $adressY , 'utf-8' );
$adressY -= 12;
}
//add page to pdf document
$pdf->pages[] = $page;
//save pdf
$pdf->save( $this->getOption( 'path' ) );
}
It could be that the pdf doesn't understand \t.
Try replacing it with 'chr(9)' which is the ascii value of the tab character. For example:-
$tab = chr(9);
$adressText = array(
'Kundennummer' . $tab . $this->_user->getUserIdString(),
'Belegnummer' . $tab . $this->_payin->getPayinIdString(),
// etc..
);
Correction:
As you have to supply the x,y coordinates to Zend_Pdf_Page::drawText() things like tabs, line feeds, etc will not work.
You will have to set fixed coordinates for your tab stops.
For example:-
$tabs = array(5, 20, 30, 50);
$page->drawText("At 1st tab", $tabs[0], 10);
$page->drawText("At 2nd Tab", $tabs[1], 10);
$page->drawText("At 3rd Tab", $tabs[2], 10);
Hopefully you get the idea.

Categories