PHPExcel generated Excel Error - Links cannot be updated - php

My PHPExcel generated excel contains a barchart and a pie chart and is automatically fired to an email. When the email attachment is downloaded and opened (you have to click enable editing) it displays this alert box:
When the email attachment is downloaded and opened (you have to click enable editing) it displays this alert box:
and behind this you can see the expected data in their cells and a blank canvas for the charts.
I close the excel document and open it again, this time I get the expected chart displayed along with data sets overlayed by this alert box:
I close the excel document and open it again, this time I get the expected chart displayed along with data sets overlayed by this alert box:
Clicking on the update link in the second alert box resolves to launching the first alert box. Clicking continue in that resolves to the chart going blank, only showing a blank canvas with axis.
My code uses extensive variables to determine the cell location for each data field. I tried using EXIT at the end of the script as advise by one of the answers around here. That didn;t work.
Code Sample:
// Add some data
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A'.$StartRow, 'Date')
->setCellValue('B'.$StartRow, $ndate)
->setCellValue('C'.$ParticipantStartLabel, 'Enrolled')
->setCellValue('D'.$ParticipantStartLabel, 'Logged In')
->setCellValue('E'.$ParticipantStartLabel, 'Yet to Log In')
->setCellValue('F'.$ParticipantStartLabel, 'Monitors (BOI, EDC and AMI)')
->setCellValue('B'.$ParticipantStartDetails, 'Participants on the program')
->setCellValue('C'.$ParticipantStartDetails, $ParticipantEnrolled)
->setCellValue('D'.$ParticipantStartDetails, $ParticipantLoggin)
->setCellValue('E'.$ParticipantStartDetails, $ParticipantYettoLog)
->setCellValue('F'.$ParticipantStartDetails, $Monitors) //$Monitors
->setCellValue('A'.$CoursesStartRow, 'S/N')
->setCellValue('B'.$CoursesStartRow, 'Course')
->setCellValue('C'.$CoursesStartRow, 'Enrolled')
->setCellValue('D'.$CoursesStartRow, 'Completed')
->setCellValue('E'.$CoursesStartRow, 'Incomplete');
//print courses for single dataset
for( $i = 0 ; $i < $NumCourses; $i++ ){
$newi = $i + 1;
$newCoursesStartRow = $CoursesStartRow + $newi;
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A'.$newCoursesStartRow, $newi)
->setCellValue('B'.$newCoursesStartRow, $Courses[$i]) // continue to Add some data on courses
->setCellValue('C'.$newCoursesStartRow, $CoursesEnrolled[$i])
->setCellValue('D'.$newCoursesStartRow, $CoursesCompleted[$i])
->setCellValue('E'.$newCoursesStartRow, $CoursesIncompleted[$i]);
}
Any help to decipher why the document would not just open with displaying this distracting alert boxes is appreciated.

It's called security, and Microsoft have applied it in all recent versions of MS Excel. The purpose is to prevent any malicious excel files from executing arbitrary code. Unfortunately, because some people have chosen to use Excel spreadsheets for malware, Microsoft have chosen to provide these warnings to indicate that they can't guarantee that this spreadsheet may contain dangerous content, and that the user opening it must make a conscious decision to accept the risks.
Generally, you would only get this error if the spreadsheet references other spreadsheet files, or if it tries to access remote data. Are you building your file froma template that may contain these?

Related

PhpSpreadsheet cell validation rules to disallow invalid entry

I am using PhpSpreadsheet within a Laravel app to output a spreadsheet that needs fairly strict controls around it in order to allow that same spreadsheet to be input back into the app after data has been entered.
I can control the data types and even have a nice pop-up message when a user enters an incorrect type such as this:
However, once the user clicks OK or Cancel, the incorrectly formatted text is allowed to remain in the cell. Is there a way to not only flag it for the user, but disallow the incorrect entry altogether?
Current example code:
if($sub['type'] === 'date') {
$ws->getStyle('C' . $row)->getNumberFormat()->setFormatCode(
\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DMYSLASH
);
$objValidation = $ws->getCell('C' . $row)->getDataValidation();
$objValidation->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_DATE);
$objValidation->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION);
$objValidation->setAllowBlank(true);
$objValidation->setShowInputMessage(true);
$objValidation->setShowErrorMessage(true);
$objValidation->setShowDropDown(true);
$objValidation->setErrorTitle('Input error');
$objValidation->setError('Please enter a date in the format d/m/yy only.');
}
I'm guessing I've missed something in the PhpSpreadsheet manual? I've looked into the base code on some of the methods like setAllowBlank, but I'm likely not looking in the right place.
I still couldn't find this in the docs (though I'm sure it is there somewhere). But once I was able to figure out where to look in the PhpSpreadsheet code, I found it. Very elegant solution from PhpSpreadsheet... I just couldn't see it in the area of base code I was looking into!
Easy fix, change one word:
$objValidation->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION);
Becomes:
$objValidation->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_STOP);
The big '!' on the popup gave me a clue to look at their style code rather than commands code. This brings up the same box, but with an 'X' and prevents changing the cell if not valid, which is exactly what I wanted.
Hopefully helps someone else in future.
Why not blanking the cell after validation error there is an isValid function. The code can look like:
if(! PhpOffice\PhpSpreadsheet\Cell\DataValidator::isValid($yourCell)){
$yourCell->setValue("");
}

Script/bot to open a link inside an email

I want download a report that I'm receiving every day on my inbox.
This email contains a link to a platform (where I have to be logged-in on the platform to open the link correctly, otherwise I will be redirected to login page) and finally there is another link that downloads the report to my computer.
My question is: It's possible to make a PHP script that can do this automatically?. All the process to read the email and identify the link it's easy, I want some guidelines to continue working.
Thanks!
This may be harder than you anticipate and PHP may not be the best language to achieve what you are after as it can not run on top of Outlook or any other desktop based email client. To do this you would have to run the PHP code from the command line, and have it set to regularly intercept all your emails and check to see if the email is from a specific user, and if it is parse the email for the two necessary links. Once you have the links you can have the code establish a cURL connection to the login form and pass the username and password, ensuring to pass any cookies defined from the authenticated session, and then establish a new cURL link to the download link to download the file to the local file system, after which you can send a new email to yourself attaching the file as a native attachment, dependant on file size.
Information on sending cookies with cURL can be found at How can I send cookies using PHP curl in addition to CURLOPT_COOKIEFILE?
The net result though is that this would have to run in the background continuously and would have to be set to regularly connect to your email server and check all emails for the existence of emails from the automated email sender.
An easier solution would be to find out if the automated tool can be setup to simply send the file as an email attachment so that you don't have to run the excess code. In addition any time the initial email structure changes or the download or login links change you would have to update the code to deal with the associated changes.
Main point is that PHP isn't the most ideal solution for what you are trying to do and what you are trying to do, in any language, is going to be a complex task to achieve.
When you already have the email link you could login to the platform using a curl request and afterwards make the same call again. the second time you'd be logged in and curl would download your report.
You could use the cURL library.
How does your platform identifies you ? If you can use cookies, look for
CURLOPT_COOKIE
curl_setopt($ch, CURLOPT_COOKIE, session_name() . '=' . session_id());
i have the a similar issue, i want to open on googlesheets a series of reports from my email, managed to do it when its attached evenif is a zip, but when its only a link o cannot do it, heres the script i use, maybe someone could upgraded to open links and import the csv
function importCSV() {
// Change the report name Report
var threads = GmailApp.search("subject:XXXXXX has:attachment from:XXXXX#google.com newer_than:1d");
var message = threads[0].getMessages()[threads[0].getMessages().length-1];
var allAttachment = message.getAttachments();
var attachment = allAttachment[0];
var contentType = attachment.getContentType();
var name = attachment.getName();
if (attachment.getContentType() === "text/csv") {
// Change the sheet name, where you want the data to appear
var sheetActive = SpreadsheetApp.openById("1slVepI8s2Ekdiha0u4NpqFLZ4NnJrhyc8in9hYNzJA0");
var sheet = sheetActive.getSheetByName("Youtube");
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
// This clears the document from previous data
sheet.clearContents().clearFormats();
// Import the CSV file to the spreadsheet
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
else if (attachment.getContentType() === "application/zip") {
attachment.setContentTypeFromExtension();
// Unzip Attachment Change the sheet name, where you want the data to appear
var sheetActive = SpreadsheetApp.openById("1slVepI8s2Ekdiha0u4NpqFLZ4NnJrhyc8in9hYNzJA0");
var sheet = sheetActive.getSheetByName("Youtube");
try {
var unzip = Utilities.unzip(attachment)[0];
var csv = unzip.getDataAsString();
var csvData2 = Utilities.parseCsv(csv, ",");
// This clears the document from previous data
sheet.clearContents().clearFormats();
// Import the CSV file to the spreadsheet
sheet.getRange(1, 1, csvData2.length, csvData2[0].length).setValues(csvData2);
} catch (e) {
// Logs an ERROR message.
console.error('myFunction() yielded an error: ' + e);
}
}}

Excel 2010 Download CSV with dynamic name from secure website

I am wanting to login to a site, navigate to a page, then download the .CSV file that will always end with a dynamic string due to it being 'custom'.
I have tried to access the site by recording a macro. However, as the data is not in a table the macro recorder is not able to pick up the actual address of the .csv file.
The display text is always:
Results [link]Click to Download[/link]
The html values are always:
<td class="smallText"><b>Results</b> <a href="vendor_report.php?report=custom [insert extremely long string here] ><u>Click to Download</u></a></td>
Without using a table, is there a way to get to this .csv & save it to my PC?
I am aware that the use of <td> denotes it is part of a table, but it is definitely not picking it up, I've gone through the site using the macro recorder and it's not picking up the inner contents from the page.
https://[domain].php?vf=vieworders
I had also thought to navigate to the site page, highlight the text, copy & paste to a spare sheet in my book, then use some code L42 previously wrote here (below) however I can't even get the copy & paste to work correctly.
For Each hlink In ThisWorkbook.Sheets("NameOfYourSheet").Hyperlinks
Set wb = Workbooks.Open(hlink.Address)
wb.SaveAs saveloc & hlink.Range.Offset(0,1).Value & ".xlsx"
wb.Close True
Set wb = Nothing
Next
Please advise. Thank you in advance.
UPDATE
I have found which table this is hiding in, Table 2. It is however in the midst of a lot of other text.
When I have copied & pasted the table contents to my sheet, I have problems getting the link to show as it's HTML value so I can then use that with my 2nd option (open links from spreadsheet).
This could be an issue with the original Get Data code I am using.
This is how it looks. The cells either side are filled, as well as that huge chunk of (blanked out) text in B20
Could Regex be of use here??
You could try using the XMLHTTP object with a stream:
Sub SO()
Dim objStream As Object, strURL As String
Set objStream = CreateObject("ADODB.Stream")
strURL = "vendor_report.php?report=custom [insert extremely long string here]"
With CreateObject("Microsoft.XMLHTTP")
.Open "GET", strURL, False
.Send
If .Status = 200 Then
objStream.Open
objStream.Type = 1
objStream.Write .ResponseBody
objStream.SaveToFile "C:\users\bloggsj\output.csv", 2
objStream.Close
End If
End With
Set objStream = Nothing
End Sub
Change the save path as required.

How can I make this PHP code more efficient? (Editing a line in a CSV file)

This code works, but I just hacked it together with my limited knowledge of PHP and I'm sure there's a more elegant and efficient way to go about it. If you'd be so kind as to point out how I can improve, that would be great!
So I have a CSV file, structured like so:
Code Class Value Status Date Created Date Redeemed
========================================================================
a51f3g45 gold 50 valid 2012-08-20
4f6a2984 silver 200 redeemed 2012-08-23 2012-08-27
gf3eb54b gold 150 valid 2012-08-30
etc...
The user fills out a form to change the Class, Value, and Status fields of a given line. I cobbled together the following code to replace the old values with the new ones:
$file = 'codes.csv';
$old_csv_string = file_get_contents($file);
preg_match('/('.$_POST['code'].',.*,.*,.*,.*,.*)\n/',$old_csv_string,$matches);
$old_row = $matches[1];
preg_match('/'.$_POST['code'].',(.*,.*,.*),.*,.*\n/',$old_csv_string,$matches_part);
$old_row_part = $matches_part[1];
$new_row_part = $_POST['class'].",".$_POST['value'].",".$_POST['status'];
$new_row = str_replace($old_row_part,$new_row_part,$old_row);
$new_csv_string = str_replace($old_row,$new_row,$old_csv_string);
file_put_contents($file,$new_csv_string);
So can I do better than 10 lines of code? Any advice would be greatly appreciated :)
Note: I tried using fgetcsv, but I couldn't figure out how to find the unique code within a 2D array, then replace its siblings.
Why are you doing this ?
I think you should store the data in a SQL table.
Each time user update data, do it in the table.
If you want the CSV to be downloadable at any moment. Use a .htaccess to redirect your.csv to csv_generator.php only if your.csv does not exist.
csv_generator.php will regenerate the whole csv if it does not exist, save it on hard drive for later use, and send it with correct mime/type in header (so it's transparent for user). User don't see he is requesting a php page.
Then you need to delete the csv on hard drive each time someone update the data (so it will be regenerated on next request)
I think this is the way to have an always ready to download csv online.
Do you know google doc does this ? Users can change data in a spreadsheet wich is available to download as a csv from a url (you need to publish this spreadsheet as a csv file).
Try using split like that for each line:
list($code, $class, $value, $status, $created, $redeemed) = split(",", $line, 6) ;
Thus you will have each field in separate variable.
Of course you need to take care of the first row in case you don't want to copy header.

Counter in ActionScript 3.0 with...PHP or?

I am doing this flash banners for multiple clients and one major request is to have some sort of counter so they know how many times the banner has been clicked.
I know how to do it in ActionScript 3.0, I make a simple var:int and i increase it +1 when a click is made on the banner. What do I do with the value of this var(say its 121) where do I store it online so its safe and can be changed by multiple flash banners(as3).
But how do I save this information so next time when the banner is loaded(on diffrent webpages) the number of clicks is whatever it was last time it was loaded.
Should I look into PHP for that ? I have no clue how to do this... some examples, tutorials, whatever works... would be much appreciated.(I am a designer, not programmer...please dont speak php-ish, or you know... :D)
I've googled a bit, and found some help, but i am still confused, and much of it its not AS3, I'm thinking maybe stuff has evolved a bit since the stuff that I found(2008)...
Thank you very much.
You'd have to store (and fetch) the value somewhere - either in the DB, in a text-file, ...
I'd go search for a tutorial on PHP+MySQL. If you don't like PHP-ish, you're probably better of finding another solution though :p
Example tutorial: http://www.freewebmasterhelp.com/tutorials/phpmysql
You need to store the data you want be retrievable/update-able from multiple clients, to be stored on a server.
You can use any server side language with a database.
Server Languages : PHP, ASP.net, JSP, ColdFusion
Database : MySQL, MSSQL, PostgreSQL, Oracle, DB2 etc..
Use whatever combination you are comfortable with.
In general:
You have a web app that increments the counter in the database
call the page using URLLoader from your AS3 banner.
Database
counter_table
-------------
counter INT
PHP File
$db = mysql_connect('localhost', 'mysql_user', 'mysql_password');
mysql_select_db('database_name');
mysql_query('UPDATE counter_table SET counter = counter + 1');
AS3 Banner
// url request with your php page address
var scriptRequest:URLRequest = new URLRequest("http://www.example.com/script.php");
// loader
var scriptLoader:URLLoader = new URLLoader();
// load page to trigger database update
scriptLoader.load(scriptRequest);
Do you also want to retrieve the value of the number of clicks in Banner ?
Easy solution (really not the best :) You should use one of the other answers.. anyways, make a php file that reads txt file containing the count of visits.. and in your flashbanner just call the php file. It'll add one hit per call..
PHP:
<?php
/**
* Create an empty text file called counterlog.txt and
* upload to the same directory as the page you want to
* count hits for.
*
*
* #Flavius Frantz: YOU DONT NEED THESE:
* Add this line of code on your page:
* <?php include "text_file_hit_counter.php"; ?>
*/
// Open the file for reading
$fp = fopen("counterlog.txt", "r");
// Get the existing count
$count = fread($fp, 1024);
// Close the file
fclose($fp);
// Add 1 to the existing count
$count = $count + 1;
// Display the number of hits
// If you don't want to display it, comment out this line
//echo "<p>Page views:" . $count . "</p>";
// Reopen the file and erase the contents
$fp = fopen("counterlog.txt", "w");
// Write the new count to the file
fwrite($fp, $count);
// Close the file
fclose($fp);
?>
Example code from: (google: php counter file) http://www.totallyphp.co.uk/text-file-hit-counter
Code is not tested, but looks ok. I only commented just a little..

Categories