i'm trying to read excel file like this:
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$spreadsheet = $spreadsheet->load(public_path("dispoP.xlsx"));
But i get this error:
Argument 1 passed to PhpOffice\PhpSpreadsheet\Reader\Xlsx\Styles::__construct() must be an instance of SimpleXMLElement, bool given, called in /Applications/XAMPP/xamppfiles/htdocs/daniele_ecommerce/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 567
Version phpspreadsheet
"phpoffice/phpspreadsheet": "^1.9",
PHP Version
7.3.24
I saw in library package that this return "false" when instead should be instance SimpleXMLElement ?
$xmlStyles = simplexml_load_string(
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
'SimpleXMLElement',
Settings::getLibXmlLoaderOptions()
);
thank you! i lost my sunday with this error :)
There is a slight error in the call you mention, but I don't think it's that:
$this->securityScanner->scan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")),
should be
$this->securityScanner->scan($this->getFromZipArchive($zip, "{$dir}/{$xpath['Target']}")),
The problem has to be indeed where you say.
The simplest thing to do would be to dump the argument to simplexml_load_string() or, possibly, the whole kerfuffle, mainly $dir/$xpath[Target]. You can open the XLSX file as a Zip (just change the extension to .zip) and verify whether the XML file inside is intact and valid.
If it is, this means that the "security Scanner" somehow renders it into something that simplexml_load_string() does not parse - maybe an empty string.
Related
I have got a PHP script that searches the current directory for MP3 files. I want to be able to get the metadata on the file and assign that to variables.
I am currently trying to use the Mp3Info library but it's complaining when I create an instance of it with a line that says
Undefined type 'wapmorgan\Mp3Info\Mp3Info'
How can I get this working?
<?php
use wapmorgan\Mp3Info\Mp3Info;
/* Scan dir for files */
$files = glob("*.mp3"); // all files ending with mp3.
/* sort files according to their upload time. */
usort($files,
function ($a, $b) {
return filemtime($a) < filemtime($b);
}
);
for ($i = 0; $i < sizeof($files); $i++) {
$trackName = basename($files[$i]);
// echo $trackName . "** **";
// create path string for the current file
$songPath = './';
$songPath .= $trackName;
// echo $songPath;
$track = new Mp3Info($songPath, true); // MY PROBLEM SEEMS TO BE APPEARING HERE
echo $track;
/* Insert data into db after creating variables here */
}
Welcome to PHP.
Error/warning/info messages
Just like other scripting/programming languages in PHP you almost always also get a line number to seek to instead of a textual message only, so you don't have to guess where the issue occured. In the case of
<?php
use wapmorgan\Mp3Info\Mp3Info;
new Mp3Info( 'music.mp3' );
...you get a very distinctive message:
Fatal error: Uncaught Error: Class 'wapmorgan\Mp3Info\Mp3Info' not found in example.php:4
Stack trace:
#0 {main}
thrown in example.php on line 4
Do you spot your script filename, followed by a colon and the number 4? Both times? It's the line number. The message even says so in the stack trace. Of course: read error/warning/info messages in its original and not interpreted by your web browser as HTML. In other words: press Ctrl+U to see more linebreaks.
See more at PHP Manual > Language Reference > Errors: Basics.
(Source) File inclusion
Just like other scripting/programming languages external declarations aren't magically included into your code - you have to tell so by via include or require. You haven't done so, which is why Mp3Info cannot be resolved by PHP. The correct code would be:
<?php
require( './Mp3Info.php' ); // Include _Mp3Info_'s source file with its declarations
use wapmorgan\Mp3Info\Mp3Info;
new Mp3Info( './music.mp3' );
Now there's no error anymore in your code. Of course: Mp3Info can still cause/throw errors, f.e. when the given file doesn't exist.
Data types
Just like other scripting/programming languages PHP knows different data types, f.e. string, array and object. Likewise you cannot use every possible combination of data type and function. Mp3Info's constructor will not return a string - it will return an object. Creating an instance of a class will always result in an object.
echo is meant for data types that can be converted into string (such as int and float and boolean). But an object cannot be converted into string, so using echo $object will yield an error. You need to look for something else:
use print_r() to print all properties of the object at once, or
use one of the object's property, because that can be converted to string and then used in echo (or print).
Complete working example
<?php
require( './Mp3Info.php' ); // Wherever that source file resides
use wapmorgan\Mp3Info\Mp3Info;
$obj= new Mp3Info( './music.mp3', TRUE ); // Also parse tag frames
// Print all object properties at once. Don't interpret as HTML.
header( 'Content-Type: text/plain' );
print_r( $obj );
// Print one chosen property's value only.
print( $obj-> tags['song'] );
Mp3Info
That's a questionable class/library - just search for need to to see what it misses. It will also only expect ID3v1 and ID3v2 tags in an MP3 files - not in other files and no other metadata as well. Which is by far not complete: see ID3 Parser and Editor and Where is the ID3v2 documentation?. Although not being perfect either, I recommend trying getID3, which supports much more in any way.
so I am trying to edit an xml file using php's simplexml extension but I am getting some problems and its
when I tried
$settings = simplexml_load_file("settings.xml");
....
if(isset($aInformation['cName']))
{
$settings->general->communityname = $aInformation['cName'];
$settings->asXML();
}
but I failed with the saving step...
$settings = simplexml_load_file("settings.xml");
$xmlconfigs = new SimpleXMLElement($settings);
....
if(isset($aInformation['cName']))
{
$settings->general->communityname = $aInformation['cName'];
$xmlconfigs->asXML();
}
but I failed too with the error
String couldn't be parsed to XML...
and I had tried searching on those posts before but they are the same as my failed example codes something edit XML with simpleXML and PHP SimpleXML error update xml file
Second one is not possible as SimpleXMLElement can only take a well-formed XML string or the path or URL to an XML document. But you are passing an object of class SimpleXMLElement returned by simplexml_load_file. That is the reason it was throwing error String couldn't be parsed to XML...
In first one the asXML() method accepts an optional filename as parameter that will save the current structure as XML to a file.
If the filename isn't specified, this function returns a string on
success and FALSE on error. If the parameter is specified, it
returns TRUE if the file was written successfully and FALSE
otherwise.
So once you have updated your XML with the hints, just save it back to file.
$settings = simplexml_load_file("settings.xml");
....
if(isset($aInformation['cName']))
{
$settings->general->communityname = $aInformation['cName'];
// Saving the whole modified XML to a new filename
$settings->asXml('updated_settings.xml');
// Save only the modified node
$settings->general->communityname->asXml('settings.xml');
}
I want to select a XML file from my computer to be parsed. The form works and I can use the Input::file('file'); function. However I want to parse this document by favour with uploading it only as temporary file. When I want to parse it I get errors like: "unable to parse from string". It seems that parser can't find the file. I tried two parsers: SimpleXML and XMLParser(from orchestral).
public function uploadFile(Request $ file){
$data =Input::file('file');
$informationdata = array('file' => $data);
$rules = array(
'file' => 'required|mimes:xml|Max:10000000',
);
$validator= Validator::make($informationdata, $rules);
if($validator->fails()){
echo 'the file has not the correct extension';
} else{
XmlParser::load($data->getRealPath());
}
I also tried to parse it after storing the file.
private function store($data){
$destinationPath = public_path('uploads\\');
$fileName = $data->getClientOriginalName();
$data->move($destinationPath,$fileName);
$xml = simplexml_load_file($destinationPath.$fileName);
}
Thanks in advance for helping.
When you say "parse" what do you mean? Find nodes? Delete nodes? Add nodes? Or only read nodes?
Because you can find and read with the SimpleXMLElement class but if you want to add or delete I suggest you to use DomDocument instead.
Using SimpleXMLElement, the construct would be:
$xml = new SimpleXMLElement($destinationPath.$fileName, null, true);
While the DomDocument would be:
$xml = new DomDocument('1.0', 'utf-8'); // Or the right version and encoding of your xml file
$xml->load($destinationPath.$fileName);
After you create the object, you cand handle all the document.
It is unknown, whether you want to validate some exiting xml-file on your computer or want to implement the ability for users to upload any xml file and write some logic to cope this task. However, this is not the point.
I would recommend you to use the built-in to PHP core simplexml_load_file() function which has helped me with the project. Because you will never get Laravel to parse xml into some decent understendable array or object to work with through Request $file injections etc. This is good to work with html-forms or json, not with xml or other formats.
That's why you should work with object which will be the result of (for example) such code:
$xml_object = simplexml_load_file($request->file('action')->getRealPath());
And then you'll need to verify every xml node and field by yourself, writing some logic as you lose the possibility of using built-in to Laravel Illuminate\Http\Request validate() method.
I have a blob resource from my db. I want to wrap temporaly this file into Symfony File object because I want to use specific methods like the extension guesser, and apply symfony file validators.
I want to store this temporary file into memory, because the blobs are small files and i dont want to create a file in disk in every request.
I tried to do this in that way:
$file = new File ('php://temp');
but symfony throws an error that says 'The file "php://temp" does not exist'. Looking at File source, the error is caused by a "is_file($path)" check that is made in the constructor, and I can invalidate this putting false in the second argument. But, if I do:
$file = new File ('php://temp', false);
the File is created, but then the error comes back later, e.g. when i use the guesser:
$file->guessExtension($file)
because in Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php:
public function guess($path)
{
if (!is_file($path)) {
throw new FileNotFoundException($path);
}
(...)
Ok. Then my question is: There is a way to load a 'php://temp' or 'php://memory' within a File object?
Pretty sure php://temp writes to memory until it is full and then writes to a file, whereas php://memory ensures only in memory with no fall back.
This likely happens because php://temp and php://memory are non-reusable, so once you've written to it the content may not still be there when you next want it. From the PHP manual:
php://memory and php://temp are not reusable, i.e. after the streams have been closed there is no way to refer to them again.
file_put_contents('php://memory', 'PHP');
echo file_get_contents('php://memory'); // prints nothing
How are you writing to php://temp to begin with? That will be the more important issue rather than with Symfony's File class. I suspect that by the time you are creating a File instance that php://temp has already gone.
It's worth noting that using php://temp will create a file on disk in the temporary location, so you might as well use write to a tempnam() handle anyway. At least then you will have a reference to a physical (but temporary) file.
I suggested to allow passing the file contents (instead of the path) to Symfony's MIME type guesser, to enable guessing "on-the-fly": https://github.com/symfony/symfony/issues/40916
Here's how I do it right now:
use Symfony\Component\Mime\MimeTypes;
$tmpFilename = tempnam(sys_get_temp_dir(), 'guessMimeType_');
file_put_contents($tmpFilename, $content);
$mimeTypes = new MimeTypes();
$guessedMimeType = $mimeTypes->guessMimeType($tmpFilename);
unlink($tmpFilename);
The first line is taken from https://www.php.net/manual/en/function.tempnam.php#93256
Why can't I use PHP in an .xml file at the same time grab it with SimpleXMLElement? When one works, the other doesn't.
Example: If I use PHP in the .xml file like
file.xml.php
<?php
require('db.php');
header('Content-Type: application/xml; charset=utf-8');
$updated_date = date('l', filemtime('file.xml.php'));
?>
<?xml version="1.0" encoding="UTF-8" ?>
<content>
<value name="Content 1" val="Value 1"></value>
<value name="Content 2" val="Value 2"></value>
<value name="Content 3" val="Value 3"></value>
<value name="Last Updated" val="<?php echo $updated_date; ?>"></value>
</content>
It works fine. But if I use SimpleXMLElement to get the file:
$xmlstring = file_get_contents('file.xml');
$xmlObject = new SimpleXMLElement($xmlstring);
foreach($xmlObject->children() as $node) {
$arr = $node->attributes();
echo $arr['name'] . ':' . $arr['val'];
}
it gives me this error:
PHP Fatal error: Uncaught exception 'Exception' with message 'String could not be parsed as XML' in /var/www/html/get_xml.php:336\nStack trace:\n#0 /var/www/html/get_xml.php(336): SimpleXMLElement->__construct('<?php??require(...')\n#1 {main}\n
I know it's telling me that the xml file cannot be read. However, when I read the xml file through its own URL, it works fine as if it was just another xml file.
Is it not possible to use PHP in .xml files and grab them at the same time? Without PHP, the file is kind of useless to me. Unless if I can just use the plain name so that it doesn't show that error. I know it has to do something with the require.
When you're getting the file, you need to ensure it's actually being parsed by PHP first. If you're just getting the PHP/XML source file from disk, it will still contain the PHP code: The code won't have been executed, meaning you'll simply have an invalid XML file.
As you've already found out, grabbing the file in a browser, it's fine: You can simulate this via PHP by using file_get_contents($urlToTheXmlPhpFile). Note, this has to be a URL to the file via a webserver: If you're just using a path to a file on your local disk, this won't work and you'll have the same problem - PHP won't have executed the file, so it will be a malformed combination of XML and PHP still.
To clarify:
file_get_contents('myfile.xml.php'); // Malformed - Attempting to parse source code.
file_get_contents('http://mydomain/myfile.xml.php'); // This should work.
If you're simply trying to require the PHP XML file via your local filesystem, rather than via a webserver, you could use eval to execute the PHP code. Do so with caution though, as this has the potential to enable arbitrary code execution for anyone who is able to change the XML file.
$validXmlString = eval(file_get_contents('myfile.xml.php')); // Be careful with this.