I'm trying to load an Excel file from a certain source with PHPExcel. I have no control over how these Excel files are generated and they need to be opened automatically with PHPExcel without human interaction (re-saving the file, etc).
I'm getting the following error:
Fatal error: Uncaught exception 'Exception' with message 'Invalid character found in sheet title' in C:\path\to\PHPExcel\Worksheet.php on line 418
The error is occurring on the load() line, using the following code to open the file:
$reader = PHPExcel_IOFactory::createReader('Excel5');
$excel = $reader->load($filename_xls);
The sheet title is irrelevant to us, so is it possible to just ignore it? Thus ignoring the error?
You don't really need to hack the core, just add this in your own code:
// $invalidCharacters = array('*', ':', '/', '\\', '?', '[', ']');
$invalidCharacters = $worksheet->getInvalidCharacters();
$title = str_replace($invalidCharacters, '', $title);
Worksheet.php exposes getInvalidCharacters() public function you can use. or get lazy and use the array() directly (copy&paste from Workbook.php definitions)
We've just done this to get it sorted for now. It's probably horribly bad and I wouldn't really advise other people doing it, but hey, it should work for us!
On version 1.7.8 of PHPExcel, in /Classes/PHPExcel/Worksheet.php around line 414 - swap the checkSheetTitle() function for the following:
private static function _checkSheetTitle($pValue)
{
// Some of the printable ASCII characters are invalid: * : / \ ? [ ]
if (str_replace(self::$_invalidCharacters, '', $pValue) !== $pValue) {
//throw new Exception('Invalid character found in sheet title');
//Hack to remove bad characters from sheet name instead of throwing an exception
return str_replace(self::$_invalidCharacters, '', $pValue);
}
// Maximum 31 characters allowed for sheet title
if (PHPExcel_Shared_String::CountCharacters($pValue) > 31) {
throw new Exception('Maximum 31 characters allowed in sheet title.');
}
return $pValue;
}
You may passing special character at title. Please check the text before passing it it to title.
$sheet2->setTitle($sub_menu_title);
Related
I'm working on Laravel (v5.7) app that converts uploaded CSV (with contacts) into array that is then passed as argument when job class is being dispatched.
Here is the example of CSV file (format that is supported):
123456,Richard,Smith
654321,John,Doe
Uploaded (CSV) file is handled like this:
$file_path = $request->file_name->store('contacts');
$file = storage_path('app/' . $file_path);
$contactsIterator = $this->getContacts($file);
$contacts = iterator_to_array($contactsIterator); // Array of contacts from uploaded CSV file
protected function getContacts($file)
{
$f = fopen($file, 'r');
while ($line = fgets($f))
{
$row = explode(",", $line);
yield [
'phone' => !empty($row[0]) ? trim($row[0]) : '',
'firstname' => !empty($row[1]) ? trim($row[1]) : '',
'lastname' => !empty($row[2]) ? trim($row[2]) : '',
];
}
}
Finally, $contacts array is passed to a job that is dispatched:
ImportContacts::dispatch($contacts);
This job class looks like this:
public function __construct($contacts)
{
Log::info('ImportContacts#__construct START');
$this->contacts = $contacts;
Log::info('ImportContacts#__construct END');
}
public function handle()
{
Log::info('ImportContacts#handle');
}
... and everything worked fine (no errors) until I've tried with this CSV:
123456,Richardÿ,Smith
654321,John,Doe
Please notice ÿ. So, when I try with this CSV - I get this error exception:
/code_smsto/vendor/laravel/framework/src/Illuminate/Queue/Queue.php | 91 | Unable to JSON encode payload. Error code: 5
... and my log file looks like this:
error local 2019-11-11 17:17:18 /code_smsto/vendor/laravel/framework/src/Illuminate/Queue/Queue.php | 91 | Unable to JSON encode payload. Error code: 5
info local 2019-11-11 17:17:18 ImportContacts#__construct END
info local 2019-11-11 17:17:18 ImportContacts#__construct START
As you can see - handle method was never executed. If I remove ÿ - no errors and handle is executed.
I've tried to solve this, but without success:
Apply utf8_encode:
protected function getContacts($file, $listId)
{
$f = fopen($file, 'r');
while ($line = fgets($f))
{
$row = explode(",", $line);
yield [
'phone' => !empty($row[0]) ? utf8_encode($row[0]) : '',
'firstname' => !empty($row[1]) ? utf8_encode($row[1]) : '',
'lastname' => !empty($row[2]) ? utf8_encode($row[2]) : '',
];
}
}
... and it works (no errors, no matter if there's that ÿ), but then Greek and Cyrillic letters are turned into question marks. For example, this: Εθνικής will become ???????.
I also tried with mb_convert_encoding($row[1], 'utf-8') - and it doesn't turn Greek or Cyrillic letter into question marks, but this ÿ character will become ?.
Move "handling" (converting to array) of uploaded CSV file into #handle method of a Job class worked, but then I was not able to store the data from that array into DB (MongoDB). Please see the update below.
DEBUGGING:
This is what I get from dd($contacts);:
So, it has that "b" where ÿ is. And, after some "googling" I found that this "b" means "binary string", that is, a non unicode string, on which functions operate at the byte level (What does the b in front of string literals do?).
What I understand is this: When dispatching Job class, Laravel tries to "JSON encode" it (passed arguments/data) but it fails because there are binary data (non-unicode strings).
Anyway, I was not able to find a solution (to be able to handle such CSV file with ÿ).
I am using:
Laravel 5.7
PHP 7.1.31-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Aug 7 2019 10:22:48) ( NTS )
Redis powered queues
UPDATE
When I move "handling" (converting to array) of uploaded CSV file into #handle method of a Job class - I don't get this error (Unable to JSON encode payload. Error code: 5), but when I try to store that problematic binary data with ÿ (b"Richardÿ") into MongoDB - it fails. The weird thing is that I don't get any error-exception message in log file, so I put all in try-catch like this:
try {
// Insert data into MongoDB
} catch (Exception $e) {
Log::info($e->getFile());
Log::info($e->getLine());
Log::info($e->getMessage());
}
... and this is the result:
Anyway, I believe that it failed because of b"Richardÿ", and I guess that the solution is in encoding string, but as I've mentioned - I was not able to find a solution that works:
utf8_encode works (no errors, no matter if there's that ÿ), but then Greek and Cyrillic letters are turned into question marks. For example, this: Εθνικής will become ???????
mb_convert_encoding($row[1], 'utf-8') - it doesn't turn Greek or Cyrillic letter into question marks, but this ÿ character will become ?.
iconv('windows-1252', 'UTF-8', $row[1]) - works (no errors, no matter if there's that ÿ), but when there are Greek or Cyrillic letters - it fails (I get this error exception: iconv(): Detected an illegal character in input string)
You have several ways to deal with it but I'd recommend the following two. In both cases, the idea is that you store a UTF-8 string.
A simpler approach, figure out what encoding it is out of the (your) predefined list and convert it to UTF8.
$encoding = mb_detect_encoding($content, 'UTF-8, ISO-8859-1, WINDOWS-1252, WINDOWS-1251', true);
if ($encoding != 'UTF-8') {
$string = iconv($encoding, 'UTF-8//IGNORE', $row[1]);
}
The second approach is to use a third party library outlined in this answer
I get the following error:
Catchable fatal error: Argument 1 passed to CorenlpAdapter::getOutput() must be an instance of string, string given, called in /Library/WebServer/Documents/website/php-stanford-corenlp-adapter/index.php on line 22 and defined in /Library/WebServer/Documents/website/php-stanford-corenlp-adapter/src/CoreNLP/CorenlpAdapter.php on line 95
index.php 21 and 22 contain:
$text1 = 'I will meet Mary in New York at 10pm';
$coreNLP->getOutput($text1);
corenlpAdapter.php lines 95 and onwards contain:
public function getOutput(string $text){
if(ONLINE_API){
// run the text through the public API
$this->getServerOutputOnline($text);
} else{
// run the text through Java CoreNLP
$this->getServerOutput($text);
}
// cache result
$this->serverMemory[] = $this->serverOutput;
if(empty($this->serverOutput)){
echo '** ERROR: No output from the CoreNLP Server **<br />
- Check if the CoreNLP server is running. Start the CoreNLP server if necessary<br />
- Check if the port you are using (probably port 9000) is not blocked by another program<br />';
die;
}
/**
* create trees
*/
$sentences = $this->serverOutput['sentences'];
foreach($this->serverOutput['sentences'] as $sentence){
$tree = $this->getTreeWithTokens($sentence); // gets one tree
$this->trees[] = $tree; // collect all trees
}
/**
* add OpenIE data
*/
$this->addOpenIE();
// to get the trees just call $coreNLP->trees in the main program
return;
}
Why exactly am I getting this error when text1 is a string?
I am the original author of this class. As you can see, the function getOutput looks like this:
public function getOutput(string $text){
...
}
Change that to:
public function getOutput($text){
...
}
The function tries to enforce that the input is string. The original code should work. However, it seems that in your case, PHP thinks "string" is not actually a string. Maybe the coding environment (the IDE) you are using uses the wrong character set? Or maybe you copy-pasted the code from HTML into the IDE or something like that. Thus whilst it says "string" on the screen, it's not actually a string to PHP.
If you are sure the input is a string, you can safely change the code like above. The class should then work normally.
public function getOutput($text){
.
.
.
}
For months I've been running the "Box Rest Client" lib by Angela R that employs the following code to parse curl responses from the box API:
$xml = simplexml_load_string($res);
Today, after the code loops through dozens of request/responses I generate this following error:
ErrorException [ Warning ]: simplexml_load_string(): Entity: line 9:
parser error : Comment not terminated
This happened in 2 straight attempts to run the code - and now seems to have gone away without any changes to anything.
Interested if anyone knows what is up with that?
I have put a catch for this case if its useful to anyone using this lib (for the next month or so before its deprecated by box api 2.0)
private function parse_result($res) {
try {
$xml = simplexml_load_string($res);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
return $array;
} catch (Exception $e){
$error = 'xml parsing error: '. $e->getMessage(). "<br>";
return array('status' => $error );
}
}
It's possible it is related to including two minus signs -- inside of an HTML comment. For example:
<!-- this is my comment--but not a very good one. -->
The two dashes in the middle of the comment causes problems with the parser.
I have html sending a POST request that reaches php code to process the request...I'm getting a strange error saying theres a syntax error on line 1
Parse error: syntax error, unexpected T_FUNCTION in /home/content/31/9275231/html/subscribe.php on line 1
However I don't see any errors on line 1.
Here is the code (I hid my API key info)
<?php
function isValidEmail( $email = null )
{
return preg_match( "/^
[\d\w\/+!=#|$?%{^&}*`'~-]
[\d\w\/\.+!=#|$?%{^&}*`'~-]*#
[A-Z0-9]
[A-Z0-9.-]{1,61}
[A-Z0-9]\.
[A-Z]{2,6}$/ix", $email );
}
/* Check if email has been posted */
if ( !isset($_POST['email']) ) die();
/* Validate email */
if ( isValidEmail($_POST['email']) ) {
require_once('./MCAPI.class.php');
// **************************************************************** //
// Enter your API Key from http://admin.mailchimp.com/account/api/
$api = new MCAPI('apikey');
// Enter your list's unique id from http://admin.mailchimp.com/lists/
// (click the "settings", the unique id is at the bottom of the page)
$list_id = 'list_unique_id';
// **************************************************************** //
if($api->listSubscribe($list_id, $_POST['email'], '') === true) {
echo 'successful';
}else{
echo 'Error: ' . $api->errorMessage;
}
}
else {
echo 'invalid_email';
}
One other peculiar thing: I notice that when I open this php code in textmate it looks fine, but when I open it in vim, all the code is displayed in one line with strange '^M' characters where new lines should be...any ideas?
The weird ^M characters are Windows/DOS line endings. Use this to replace them with Unix line endings:
:%s/^V^M/\r/g
More info here: http://grx.no/kb/2008/11/17/remove-windows-line-endings-in-vim/
Check the options in your text editor to see if you can make newlines as LFs instead of CRs (or both a CR followed by an LF). What's happening is your newlines are only CRs, whereas the PHP interpreter is looking for LFs for newlines, so it reads your code as one big line.
First let me say sorry for the amount of code I'm posting below I'm going to try and keep it as short as possible but this is built on top of my MVC (lightweight-mvc)
Ok So my Problem is that for some reason php is throwing a fatal error on code that should not be being used in my current code,
So how this works I have my MVC witch used the first 2 parts of the url to know what its loading, the problem is I'm building a Moulder CMS into my MVC so it's boot strapping twice,
So here is my Problem,
http://{domain}/admin/control/addon/uploader/method/uploadCheck/
I'm using the above now let me explain a little into that the /admin/control are for the main MVC System it auto-loads the Admin controller then fires the controlAction method from the controller much the same as most MVC's,
The next part are URL paramters that build an array the same as GET or POST would
array('addon'=>'uploader', 'method'=>'uploadCheck')
So from that my control action will auto load as is the code below
public function controlAction(){
global $_URL;
if(cleanData::URL("addon")){
$addonName = "addon_".cleanData::URL("addon");
$methodName = (cleanData::URL("method"))? cleanData::URL("method")."Action" : "indexAction";
echo $methodName;
$addon = new $addonName();
$addon->$methodName();
return;
}else{
$this->loadView("CMS/controll");
}
}
cleanData::URL is an abstract method that just returns the value of the key provided though addSlashes()
So as you can see from the code below it will then use the autoloader to load the module(AKA addon)
Just so you can follow the auto loader works in a simpler version of the Zend Frame work autoloader _ so you have class name addon_admin that would be inside file admin.php that is in the folder addon so the autoloader will load addon/admin.php
So As above with my URL and controlAction it's loading addon/uploader.php and as such this is the contents
<?php
class addon_uploader extends Addons{
public function uploadCheckAction(){
echo 0;
}
public function uploaderAction(){
if (!empty($_FILES)) {
$tmpFile = $_FILES['Filedata']["tmp_name"];
$newLock = "../uploads/".end(explode('/', $tmpFile).$_FILES['Filedata']['name']);
move_uploaded_file($tmpFileName, $newLock);
$POSTback = array(
'name' => $_FILES['Filedata']['name'],
'type' => $_FILES['Filedata']['type'],
'tmp_name' => $newLock,
'error' => $_FILES['Filedata']['error'],
'size' => $_FILES['Filedata']['size']
);
echo json_enocde($POSTback);
}
}
}
?>
But as you can see from my URL its using the uploadCheckAction method witch for debugging i have set so it always says false (AKA 0),
But i seem to get this error:
Fatal error: Only variables can be passed by reference in C:\xampp\htdocs\FallenFate\addon\uploader.php on line 11
But line 11 is $newLock = "../uploads/".end(explode('/', $tmpFile).$_FILES['Filedata']['name']); witch should not be being used could any one provide any help into why this would occur and how i could fix it
end() PHP Manual needs an expression of a single variable (more precisely an array), but not a function return value or any other type of expression.
I think that's basically the cause of your error, more specifically with your code:
$newLock = "../uploads/".end(explode('/', $tmpFile).$_FILES['Filedata']['name']);
you're even driving this far beyond any level of treatment PHP can cope with:
you concatenate an array with a string (which results in a string).
you run end() on that string - not on a variable, not even an array.
I have no clue what you try to do with the code, but I can try:
$filename = $_FILES['Filedata']['name'];
$parts = explode('/', $tmpFile);
$last = end($parts);
$newLock = "../uploads/". $last . $filename;
Or probably even only this:
$filename = $_FILES['Filedata']['name'];
$newLock = "../uploads/". $filename;