I am currently working on an invoice script which currently pulls the information from MySql and then converts that information into a PDF and emails it using PHPmailer.
The part im stuck with is how I would convert this into a PDF. I would like to be able to post the orderid to a following page which then does the conversion to PDF.
I have attached my script below for some help.
<?php
session_start();
$username = $_SESSION['username'];
$con = mysqli_connect('***', '***', '***', '***');
if (!isset($con)) {
die("Connection to Aurora System failed.");
}
$orderid = $_POST['order_id'];
?>
<!doctype html>
<html>
<body class="body page-orderview clearfix">
<div class="element"></div>
<p class="text text-1">SMKD Field Force</p>
<img class="image" src="images/smkd_logo.png">
<p class="text text-2">Welcome</p>
<p class="text text-3">Order <?php echo "$orderid"; ?>
<table>
<tr>
<th>Product Title</th>
<th>Nicotine Strength</th>
<th>Quantity</th>
<th>Price (inc. VAT)</th>
</tr>
<?php
$query = "SELECT `product`, `variant`, `quantity` FROM orders_detail WHERE order_id = '$orderid'";
$result = mysqli_query($con, $query);
$quantitytotal = 0;
$quantityline = - 0;
while ($row = mysqli_fetch_assoc($result)) {
$product = $row['product'];
$stuff = $row['quantity'];
$variant = $row['variant'];
$linequantity = $stuff;
$quantitytotal += $stuff;
$pricequery = "SELECT product_price FROM products WHERE product_name = '$product'";
$priceresult = mysqli_query($con, $pricequery);
$pricetag = 0;
$priceline = 0;
while ($rowprice = mysqli_fetch_assoc($priceresult)) {
$price = $rowprice['product_price'];
$pricetag += $price;
$priceline = $price;
}
$linetotal = $priceline * $linequantity;
echo '<tr><td>' . $product .' </td> ' . '<td>' . $variant . '</td>' . ' <td> ' . $linequantity . '</td>' . '<td> £' . $linetotal . '</td> </tr>';
}
$total = $pricetag * $quantitytotal;
?>
<tr><td>Total Ex Vat:</td><td> Total Inc Vat:</td></tr>
<tr><td><?php echo "£" . ($total / 1.2);?></td>
<td><?php echo "£" . $total; ?></td></tr>
</table>
</p><br>
<form method="post" action"pdfinvoice.php">
<input type="hidden" value="<?php echo $orderid; ?>" name="orderid">
</form>
Submit button goes here
</body>
</html>
I wouuld not object to converting the entire page to a PDF but from what I understand this isn't possible with FPDF.
Regards & Many thanks!
As long as you don't make it too complex in regard to styling and html elements, I suggest taking a look at https://github.com/dompdf/dompdf, it's a pretty powerfull HTML to PDF converter library and is supports quite a lot of HTML.
Just forms and the like aren't going to work inside of the pdf, so don't include those (they may or may not be rendered, depends on the exact html tag.)
I actually just completed the same task a couple weeks ago. My page doesn't display the pdf however. Upon completion of checkout the page displays a success message and emails the pdf to the user.
Once you download and include the the FPDF library in your php file. Its just a matter of creating the FPDF object, adding to it, and outputting it.
require "Resources/PDF/fpdf.php";
$pdf = new FPDF();
$pdf->SetAutoPageBreak(true, 0);
$pdf->SetLeftMargin(8);
$pdf->AddPage();
$pdf->SetFont('Arial','B',20);
$pdf->SetTextColor(255);
$pdf->SetFillColor(0,153,204);
$pdf->Cell(194,10,'MyCompany Inc.','LRT',0,'L', true);
$pdf->Ln();
$pdf->SetFont('Arial','I',12);
$pdf->Cell(97,10,'Invoice #: '.$id.''.$cnt.'','LB',0,'L', true);
$pdf->Cell(97,10, "Date: ".date("d-m-Y")." ",'RB',0,'R', true);
$pdf->Ln();
$pdf->SetTextColor(0,153,204);
$pdf->SetFont('Arial','B',14);
$pdf->Cell(40,10,'Ship to:',0,4);
$pdf->SetTextColor(0,0,0);
$pdf->SetFont('Arial','I',12);
$pdf->Cell(40,5, $_POST['shippingName'],0,5);
$pdf->Cell(40,5, $COMP,0,6);
$pdf->Cell(40,5, $EMAIL,0,6);
$pdf->Cell(40,5, $_POST['shippingPhoneNumber'],0,7);
$pdf->Cell(40,5, $_POST['shippingAddress'],0,8);
$pdf->Cell(40,5, $_POST['shippingPostalCode'],0,9);
$pdf->Cell(40,5, $_POST['shippingCity'],0,10);
$pdf->Cell(40,5, $_POST['shippingProvince'],0,11);
$pdf->Cell(40,5, $_POST['shippingCountry'],0,12);
$pdf->Output(); //should display the pdf to the page
Output("filepath"); can save pdf to directory where you could then email the file.
The above will create a header and list User's info passed in through $_POST variables.
The FPDF documentation can be helpful at times. http://www.fpdf.org/
Related
I am trying to create Pagination using PHP, trying to show 5 records per page. Everything works just fine but when I click Pagination links to go to the next page it show an error message.
Access forbidden!
You don't have permission to access the requested object. It is either
read-protected or not readable by the server.
If you think this is a server error, please contact the webmaster.
Error 403
localhost Apache/2.4.25 (Win32) OpenSSL/1.0.2j PHP/5.6.30
Here is my code.
<?php
define("SPP", 5);
if(isset($_GET['groupname']) && isset($_GET['uniname'])) {
/* VARS */
$xpage = 0;
$content = null;
$totalProfile;
$totalPage = 0;
if(isset($_GET['xpage'])) { $xpage = $_GET['xpage']; }
$start = $xpage*SPP;
$end = $start+SPP;
include("protected/config.php");
include("protected/class.db.php");
include("protected/publicLang.php");
$newSearch = new DB();
$newSearch->query("SELECT username, university,bgroup, (SELECT COUNT(id) FROM donors) AS totalProfile FROM donors WHERE bgroup = :bgroup LIMIT " . $start . ", " . $end . " ");
$newSearch->exec(array(
":bgroup" => $_GET['groupname']
));
$data = $newSearch->fetch();
foreach($data as $row) {
$totalProfile = $row['totalProfile'];
$content .= '
<tr>
<td>' . $row['username'] . '</td>
<td>'.$row['university'].'</td>
<td>' . convertBloodIdPublic($row['bgroup']) . '</td>
<td><button class="btn btn-success">Contact</button></td>
</tr> ';
}
$totalPage = round($totalProfile/SPP); }
?>
<div class="container records">
<table>
<tr>
<th>--</th>
<th>--</th>
<th>--</th>
<th>--</th>
</tr>
<?php echo $content ?>
</table>
<ul class="pagination">
<?php
for($i=1; $i<=$totalPage; $i++) {
echo '<li>' . $i . '</li>';}
?>
</ul>
403 indicates you are no longer authorized. You probably need to pass some authentication information, this is usually done by POSTING to the URL instead of GET ting it as you are now doing via a bare hyperlink/ element.
I think if you change your code to
<a href="javascript:submit_pagination($i);" >
and add a HIDDEN input element to the encompassing form and add some javascript along the lines
function submit_pagination(i){
document.forms[0].xpage.value = i;
document.forms[0].submit();
}
I think it might work. Hope it helps!
So I'm working on my very first ever attempt at pagination (using simple Previous and Next buttons) on a for-fun project that I've undertaken. Below is all of the relevant code for my pagination system - I have left out the before and after, but I assure you that the table structure is valid.
Here is the jQuery I'm using with the elements I'm using to call the script:
<ul class="pager">
<li class="previous">< Previous</li>
<li class="next">Next ></li>
</ul>
<script>
$(document).ready(function() {
var page = 1;
$(".pagination-page").hide();
$(".pagination-page tbody[id=page" + page + "]").show();
$('#pagination-prev').click(function() {
page = page - 1;
$(".pagination-page").hide();
$(".pagination-page tbody[id=page" + page + "]").show();
});
$('#pagination-next').click(function() {
page = page + 1;
$(".pagination-page").hide();
$(".pagination-page tbody[id=page" + page + "]").show();
});
});
</script>
When I viewed the page without the jQuery active, I saw 8 <tbody> elements filled with dummy data that had been properly classed and id'd by the PHP script. My issue is that when I view the page with the script active, it doesn't seem to be working out for me. It hides all .pagination-page elements as I want, but my output has nothing toggled to show. Below is the PHP that is generating the content that I am flipping through.
<?php
try {
$listed = $dbc->query("SELECT data1,data2,data3,data4 FROM `table` ORDER BY data3 DESC")->fetchAll(PDO::FETCH_BOTH);
$annPP = 15;
$totalRows = count($listed);
$lastPCount = $totalRows % $annPP;
$totalPages = ceil($totalRows/$annPP);
$place = 0;
for ($i=1;$i<=$totalPages;$i++) {
echo "<tbody class='pagination-page' id='page{$i}'>";
if ($i == $totalPages) {
// Only do the remaining rows
$pageMax = $place + $lastPCount;
} else {
// Do 15 rows
$pageMax = $i * 15;
}
for ($j=$place;$j<$pageMax;$j=$place) {
$row = $listed[$j];
echo "<tr>
<td style='width: 25%'>";
if ($isAdmin) {
echo '<label class="control-label"><input type="checkbox" name="delete[]" value="' . $row['0'] . '"> ';
}
echo "<a href='view.php?id={$row[0]}'>{$row[1]}</a>";
if ($isAdmin) {
echo '</label>';
}
echo "</td>
<td style='width: 60%'>{$row[2]}</td>
<td class='text-center' style='width: 15%'>";
$created = new DateTime($row[3]);
echo $created->format('Y/m/d') . "</td>
</tr>";
$place++;
}
echo "</tbody>";
}
}
?>
What did I miss? What's going on? Thanks!
Removing the .pagination-page to make my jQuery read as follows:
$("tbody[id='page" + page + "']").show;
Fixed the problem. Not quite sure I understand why this is, though.
I am doing a small personal web portfolio in order to learn web development. I have a list of all the stocks that I have "bought" and I would like to update the price in real-time from yahoo finance. I can already do the price update but I override the table that I display the stocks with a new one that is called using javascript.
I know there must be a cleaner way. I am trying to update the price using javascript but I don't think I am doing everything right.
Here is what I have so far.
Portfolio.php displays all the stocks I have
<?php foreach ($shares as $row): ?>
<tr >
<td><?php echo $row["symbol"];?></td>
<td><?php echo $row["name"];?></td>
<td style="text-align: right;"><?php echo $row["shares"];?></td>
<td id="price" style="text-align: right;">$ <?php echo number_format($row["price"],2);?></td>
<td style="text-align: right;"><?php
$change = number_format($row["change"],2);
echo sprintf( "%+1.2f", $change );
echo " ( ";
echo $row["pct"];
echo " )";
?></td>
<td style="text-align: right;">$ <?php echo $row["dayGain"];?></td>
<td style="text-align: right;">$ <?php echo number_format($row["total"],2);?></td>
</tr>
<?php endforeach; ?>
</table>
<script type="text/javascript" src="../html/js/update.js" ></script>
Then I have update.php which returns all the stock information from yahoo finance as a json
<?php
// configuration
require("../includes/config.php");
//query user's portfolio
$rows = query("SELECT * FROM shares WHERE id = ?", $_SESSION["id"]);
$cash = query("SELECT cash FROM users WHERE id = ?", $_SESSION["id"]);
//create array to store the shares
$shares = array();
//for each of the user info
foreach($rows as $row){
$yql_base_url = "http://query.yahooapis.com/v1/public/yql";
$yql_query = "select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20(%22".$row['symbol']."%22)%0A%09%09";
$env = "env=http%3A%2F%2Fdatatables.org%2Falltables.env";
$yql_full_query = $yql_base_url . "?q=" . $yql_query . "&format=json&" . $env;
$session = curl_init($yql_full_query);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
$json = curl_exec($session);
$stock = json_decode($json);
if($stock->query->results !== false){
$shares [] = array(
"symbol" => $stock->query->results->quote->symbol,
"price" => $stock->query->results->quote->LastTradePriceOnly
);
}
}
$return = array("price" => $shares );
echo json_encode($return);
?>
And the third file is update.js in which I am trying to have javascript
$(document).ready(function(){
function stock() {
$(function() {
$.getJSON('../update.php',function(result){
$("div#price2").html(result.price);
});
});
stock();
setInterval(stock(), 10000);
});
});
If I go directly to update.php I can view the prices as json. I think the problem lies with the update.js file but I cannot figure out what the problem is. I cannot even print Hello from update.js in the price field.
What I am trying to do is display the stocks that I have stored in the database and then update the price using ajax and javascript. Any help would be appreciated. Thanks in advance.
Use php's json functions coupled with a .getJSON to update it... Here's some example code:
// pull_stock_price.php
<?php
$return = array("content" => "New Stock Price: $2000");
json_encode($return);
?>
// Jquery to pull stock price once every 10 seconds:
function stock() {
$(function() {$.getJSON("pull_stock_price.php",function(result){
$("#StockPrice").html(result.content);
});
});
stock();
setInterval(stock, 10000);
// HTML!
<td><div id="StockPrice"></div></td>
What this does: Every 10 seconds the user's browser will pull pull_stock_price.php and will take the content provided from the json and update . You can have pull_stock_price.php pull from the database, curl or really anywhere and format the data how you want it.
I have a strange issue going on. It may be server related, but I don't know what to look for.
I have a .php page with a few Virtual Includes:
<?php virtual ("nav.shtml"); ?>
...throughout it. I have also a parser that is displaying XML data in a table form.
The parser works with the standard:
<?php include ('parser.php'); ?>
...however, if I have the Virtual above the include, the parser doesn't work. Or at least it will not "find the file" however, the file is there and it works ABOVE the virtual, displaying it fine...
For example, this works:
<?php include ('parser.php'); ?>
<?php virtual ('file.shtml'); ?>
This doesn't:
<?php virtual ('file.shtml'); ?>
<?php include ('parser.php'); ?>
Am I missing something here?
Here is the index.shtml page code:
<?php virtual ("nav.shtml"); ?>
<div id="sortabletable">
<table id="myTable" class="tablesorter">
<thead>
<tr>
<th>Subject</th>
<th>Committee</th>
<th>Witness</th>
<th>Date</th>
<th>Bill</th>
<th>Link</th>
</tr>
</thead>
<tbody>
<?php include('parser.php'); ?>
</tbody>
</table>
</div>
<?php virtual ("footer.shtml"); ?>
Here is the parser code:
<?php
$xml_file = "test.xml";
$xml_subject_key = "*TESTIMONIES*CONGRESS*SUBJECT";
$xml_committee_key = "*TESTIMONIES*CONGRESS*COMMITTEE";
$xml_witness_key = "*TESTIMONIES*CONGRESS*WITNESS";
$xml_date_key = "*TESTIMONIES*CONGRESS*DATE";
$xml_bill_key = "*TESTIMONIES*CONGRESS*BILL";
$xml_link_key = "*TESTIMONIES*CONGRESS*LINK";
$congress_array = array();
$counter = 0;
class xml_story{
var $subject, $committee, $witness, $date, $bill, $link;
}
function startTag($parser, $data){
global $current_tag;
$current_tag .= "*$data";
}
function endTag($parser, $data){
global $current_tag;
$tag_key = strrpos($current_tag, '*');
$current_tag = substr($current_tag, 0, $tag_key);
}
function contents($parser, $data){
global $current_tag, $xml_subject_key, $xml_committee_key, $xml_witness_key, $xml_date_key, $xml_bill_key, $xml_link_key, $counter, $congress_array;
switch($current_tag){
case $xml_subject_key:
$congress_array[$counter]->subject = $data;
break;
case $xml_committee_key:
$congress_array[$counter]->committee = $data;
break;
case $xml_witness_key:
$congress_array[$counter]->witness = $data;
break;
case $xml_date_key:
$congress_array[$counter]->date = $data;
break;
case $xml_bill_key:
$congress_array[$counter]->bill = $data;
break;
case $xml_link_key:
$congress_array[$counter]->link = $data;
$counter++;
break;
}
}
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "startTag", "endTag");
xml_set_character_data_handler($xml_parser, "contents");
$fp = fopen($xml_file, "r") or die("Could not open file");
$data = fread($fp, filesize($xml_file)) or die("Could not read file");
if(!(xml_parse($xml_parser, $data, feof($fp)))){
die("Error on line " . xml_get_current_line_number($xml_parser));
}
xml_parser_free($xml_parser);
fclose($fp);
// A simple for loop that outputs our final data.
//echo sizeof($congress_array);
for($x=0; $x<count($congress_array); $x++){
echo "<tr><td scope='row'>" . $congress_array[$x]->subject . "</td>";
echo "<td>" . $congress_array[$x]->committee . "</td>";
echo "<td>" . $congress_array[$x]->witness . "</td>";
echo "<td>" . $congress_array[$x]->date . "</td>";
echo "<td>" . $congress_array[$x]->bill . "</td>";
echo '<td><img src="download-icon.png" width="20" height="20" alt="' . $congress_array[$x]->subject . '"/></td></tr>';
}
?>
"Will not find the file" ... which file? The XML ? The shtml?
Without seeing your code (cough) I can only guess that your .SHTML includes some executable PHP which is upsetting things ...
But without posted code all that we can do is guess
If you use Virtual and Includes in some cases you will need to split your includes code and run it at the top of your .shtml file. Then have the output includes where you need the output. Worked for my issue.
Thanks!
I am having trouble with modifying a php application to have pagination. My error seems to be with my logic, and I am not clear exactly what I am doing incorrectly. I have had before, but am not currently getting errors that mysql_num_rows() not valid result resource
and that invalid arguments were supplied to foreach. I think there is a problem in my logic which is stopping the results from mysql from being returned.
All my "test" echos are output except testing while loop. A page is generated with the name of the query and the word auctions, and first and previous links, but not the next and last links. I would be grateful if a more efficient way of generating links for the rows in my table could be pointed out, instead of making a link per cell. Is it possible to have a continuous link for several items?
<?php
if (isset($_GET["cmd"]))
$cmd = $_GET["cmd"]; else
die("You should have a 'cmd' parameter in your URL");
$query ='';
if (isset($_GET["query"])) {
$query = $_GET["query"];
}
if (isset($_GET["pg"]))
{
$pg = $_GET["pg"];
}
else $pg = 1;
$con = mysql_connect("localhost","user","password");
echo "test connection<p>";
if(!$con) {
die('Connection failed because of' .mysql_error());
}
mysql_query('SET NAMES utf8');
mysql_select_db("database",$con);
if($cmd=="GetRecordSet"){
echo "test in loop<p>";
$table = 'SaleS';
$page_rows = 10;
$max = 'limit ' .($pg - 1) * $page_rows .',' .$page_rows;
$rows = getRowsByProductSearch($query, $table, $max);
echo "test after query<p>";
$numRows = mysql_num_rows($rows);
$last = ceil($rows/$page_rows);
if ($pg < 1) {
$pg = 1;
} elseif ($pg > $last) {
$pg = $last;
}
echo 'html stuff <p>';
foreach ($rows as $row) {
echo "test foreach <p>";
$pk = $row['Product_NO'];
echo '<tr>' . "\n";
echo '<td>'.$row['USERNAME'].'</td>' . "\n";
echo '<td>'.$row['shortDate'].'</td>' . "\n";
echo '<td>'.$row['Product_NAME'].'</td>' . "\n";
echo '</tr>' . "\n";
}
if ($pg == 1) {
} else {
echo " <a href='{$_SERVER['PHP_SELF']}?pg=1'> <<-First</a> ";
echo " ";
$previous = $pg-1;
echo " <a href='{$_SERVER['PHP_SELF']}?pg=$previous'> <-Previous</a> ";
}
echo "---------------------------";
if ($pg == $last) {
} else {
$next = $pg+1;
echo " <a href='{$_SERVER['PHP_SELF']}?pg=$next'>Next -></a> ";
echo " ";
echo " <a href='{$_SERVER['PHP_SELF']}?pg=$last'>Last ->></a> ";
}
echo "</table>\n";
}
echo "</div>";
function getRowsByProductSearch($searchString, $table, $max) {
$searchString = mysql_real_escape_string($searchString);
$result = mysql_query("SELECT Product_NO, USERNAME, ACCESSSTARTS, Product_NAME, date_format(mycolumn, '%d %m %Y') as shortDate FROM {$table} WHERE upper(Product_NAME) LIKE '%" . $searchString . "%'" . $max);
if($result === false) {
echo mysql_error();
}
$rows = array();
while($row = mysql_fetch_assoc($result)) {
echo "test while <p>";
$rows[] = $row;
}
return $rows;
mysql_free_result($result);
}
edit: I have printed out the mysql error of which there was none. However 8 "test whiles" are printed out, from a database with over 100 records. The foreach loop is never entereded, and I am unsure why.
The problem (or at least one of them) is in the code that reads:
$rows = getRowsByProductSearch($query, $table, $max);
$numRows = mysql_num_rows($rows);
The $numRows variable is not a MySQL resultset, it is just a normal array returned by getRowsByProductSearch.
Change the code to read:
$rows = getRowsByProductSearch($query, $table, $max);
$numRows = count($rows);
Then it should at least find some results for you.
Good luck, James
Hi there,
The next problem is with the line that reads:
$last = ceil($rows/$page_rows);
It should be changed to read:
$last = ceil($numRows / $page_rows);
Would recommend adding the following lines to the start of you script at least while debugging:
ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_errors', 'On');
As that would have thrown up a fatal error and saved you a whole lot of time.
if (!(isset($pg))) {
$pg = 1;
}
How is $pg going to get set? You don't appear to be reading it from $_GET. If you're relying on register_globals: don't do that! Try to read it from $_GET and parse it to a positive integer, falling back to '1' if that fails.
<a href='{$_SERVER['PHP_SELF']}?pg=$next'>Next -></a>
You appear to be losing the other parameters your page needs, 'query' and 'cmd'.
In general I'm finding it very difficult to read your code, especially the indentation-free use of echo(). Also you have untold HTML/script-injection vulnerabilities every time you "...$template..." or .concatenate a string into HTML without htmlspecialchars()ing it.
PHP is a templating language: use it, don't fight it! For example:
<?php
// Define this to allow us to output HTML-escaped strings painlessly
//
function h($s) {
echo(htmlspecialchars($s), ENT_QUOTES);
}
// Get path to self with parameters other than page number
//
$myurl= $_SERVER['PHP_SELF'].'?cmd='.urlencode($cmd).'&query='.urlencode($query);
?>
<div id="tableheader" class="tableheader">
<h1><?php h($query) ?> Sales</h1>
</div>
<div id="tablecontent" class="tablecontent">
<table border="0" width="100%"> <!-- width, border, cell width maybe better done in CSS -->
<tr>
<td width="15%">Seller ID</td>
<td width="10%">Start Date</td>
<td width="75%">Description</td>
</tr>
<?php foreach ($rows as $row) { ?>
<tr id="row-<?php h($row['Product_NO']) ?>" onclick="updateByPk('Layer2', this.id.split('-')[1]);">
<td><?php h($row['USERNAME']); ?></td>
<td><?php h($row['shortDate']); ?></td>
<td><?php h($row['Product_NAME']); ?></td>
</tr>
<?php } ?>
</table>
</div>
<div class="pagercontrols">
<?php if ($pg>1) ?>
<<- First
<?php } ?>
<?php if ($pg>2) ?>
<-- Previous
<?php } ?>
<?php if ($pg<$last-1) ?>
Next -->
<?php } ?>
<?php if ($pg<$last) ?>
Last ->>
<?php } ?>
</div>
Is it possible to have a continuous link for several items?
Across cells, no. But you're not really using a link anyway - those '#' anchors don't go anywhere. The example above puts the onclick on the table row instead. What exactly is more appropriate for accessibility depends on what exactly your application is trying to do.
(Above also assumes that the PK is actually numeric, as other characters may not be valid to put in an 'id'. You might also want to consider remove the inline "onclick" and moving the code to a script below - see "unobtrusive scripting".)
This is wrong:
if($cmd=="GetRecordSet")
echo "test in loop\n"; {
It should be:
if($cmd=="GetRecordSet") {
echo "test in loop\n";
In your getRowsByProductSearch function, you return the result of mysql_error if it occurs. In order to debug the code, maybe you can print it instead, so you can easily see what the problem is.