BinaryContent for a pdf is null - php

I am using Sonata Media Bundle to let users upload PDF files. I want to use Imagick to create a preview image of a pdf document. I have a $media object that holds information about my pdf.
When I do die(dump($media)), I see a media object that includes the following line:
#providerReference: "3c4460aae99b0084d08252065bf3eea1817842d9.pdf"
... and opening that file via:
open -a Preview ./data/storage/faq/0001/01/3c4460aae99b0084d08252065bf3eea1817842d9.pdf
... on my mac yields a fully legible PDF.
The problem is that I also see the following line in the browser:
#binaryContent: null
... which means that I can't dump the binary content into a temporary file for the purpose of having Imagick manipulate it.
How do I get a file path that I can hand off to Imagick?

Here is roughly what worked in order to get me a useful reference to a file, complete with valid binary content.
public function preUpdate(Document $document)
{
$media = $document->getMedia();
if ($media === null) {
return;
}
$mediaName = $media->getName();
if ($media->getContentType() !== 'application/pdf') {
return;
}
$context = $media->getContext();
$formats = $pool->getFormatNamesByContext($context);
if (null === $formats) {
return;
}
$provider = $this->getProvider($media->getProviderName());
$publicUrls = [];
$fullFilePath = $provider->getReferenceImage($media);
}
...
private function getPool()
{
return $this->container->get('sonata.media.pool');
}
...
private function getProvider($name)
{
return $this->container->get($name);
}

Related

Symfony, how to read and upload epub file in google storage and read it

I work with "symfony/symfony": "~3.4", and "knplabs/gaufrette": "^0.3.0", for uploading media to google storage. But how to be with epub files, when I add epub file in body post request, I had file without name or path
epubUrl = {Symfony\Component\HttpFoundation\File\UploadedFile} [7]
test = false
originalName = "RU EJTOP epub r1 (2).epub"
mimeType = "application/octet-stream"
size = 0
error = 1
*SplFileInfo*pathName = ""
*SplFileInfo*fileName = ""
and action catch error
Warning: file_get_contents(): Filename cannot be empty
from upload function, because file_get_contents required some path
public function upload(
UploadedFile $file,
$target,
$allowedMimeTypesArray,
$name
) {
if (!$allowedMimeTypesArray) {
$allowedMimeTypesArray = self::$allowedMimeTypes;
}
// Check if the file's mime type is in the list of allowed mime types.
if (!in_array($file->getClientMimeType(), $allowedMimeTypesArray, true)) {
throw new \InvalidArgumentException(
sprintf(
'Files of type %s are not allowed.',
$file->getClientMimeType()
)
);
}
$y = file_get_contents($file->getPathname());
$this->storeFile($target, file_get_contents($file->getPathname()), $name);
return $name;
}
private function storeFile($target, $data, $name)
{
/** #var GoogleCloudStorage $fileSystem */
$fileSystem = $this->getFileSystem($target);
if (false === $fileSystem->write($name, $data)) {
throw new \Exception('Storing file failed');
}
}
how to upload epub file in google storage and then read it ?
and how it works with epub file in php ?
I found, php.ini upload_max_filesize after increase it - file uploaded with path and name and get contents and write go google storage. Because need follow errors in UploadedFile class

Adding files to a Tar Archive in PHP with different filenames

I'm currently using the Archive-Tar Pear extension for PHP to add a collection of files into a Tar Archive.
These files are stored on a filer with an extra extension
e.g.
filename.tgz.104850209.t or filename2.doc.2154395.t
I'd like to remove this extra extension while adding the files so that my Tar Archive would have the files: filename.tgz and filename2.doc
Is there a way of doing that without having to copy/rename the source files first before adding to the Archive?
Thanks,
Mark.
Archive_Tar in its latest version does not yet support such a functionality out of the box. Part of the functionality is in _addFile() and the other part in _addString().
Most easy is probably to extend from Archive_Tar and proxy all calls to _writeHeaderBlock() which is public, applying a map on the filename parameter so to rename it when written into headers.
class Patched_Archive_Tar extends Archive_Tar
{
var $renameMap = array();
function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
$p_type='', $p_uid=0, $p_gid=0)
{
return parent::_writeHeaderBlock($this->_translateFilename($p_filename),
$p_size, $p_mtime=0, $p_perms=0,
$p_type='', $p_uid=0, $p_gid=0);
}
function _translateFilename($orignal)
{
$map = $this->renameMap;
if (isset($map[$orignal])) {
return $map[$orignal];
}
return $original;
}
}
Usage:
$obj = new Patched_Archive_Tar('dummy.tar'); // name of archive
$files = array('mystuff/ad.gif',
'mystuff/alcon.doc.t',
'mystuff/alcon.xls.t'); // files to store in archive
$obj->renameMap = array(
'mystuff/alcon.doc.t' => 'mystuff/alcon.doc',
'mystuff/alcon.xls.t' => 'mystuff/alcon.xls',
) // files to rename
if ($obj->create($files)) {
echo 'Created successfully!';
} else {
echo 'Error in file creation';
}
This is quick and dirty but hopefully worky. For something better see the function I noticed at the beginning _addFile() and _addString(), you basically want another one that is able to add a file (as with _addFile()) by specifiying the filename (as with _addString()).
Tried to edit #hakre's answer, but peer reviewers weren't having that.
To answer #user2248522's comment, I rewrote the class to use _writeHeader. Additionally, I added a block for any Windows users out there and fixed a couple spelling errors.
class Patched_Archive_Tar extends Archive_Tar
{
var $renameMap = array();
function _writeHeader($p_filename, $p_stored_filename)
{
return parent::_writeHeader($p_filename,
$this->_translateFilename($p_stored_filename));
}
function _translateFilename($orignal)
{
$map = $this->renameMap;
if (isset($map[$original])) {
return $map[$original];
}
//Need alter our map array to match the altered original on WIN systems
if (defined('OS_WINDOWS') && OS_WINDOWS) {
//Check for a proper array
if (!is_array($map)) return $original;
//Check each replacement rule
foreach($map as $needle => $replacement) {
if ($this->_translateWinPath($needle, true) == $original) {
return $replacement;
} //if()
} //foreach()
} //if()
return $original;
}
}
Usage:
$obj = new Patched_Archive_Tar('dummy.tar'); // name of archive
$files = array('mystuff/ad.gif',
'mystuff/alcon.doc.t',
'mystuff/alcon.xls.t'); // files to store in archive
$obj->renameMap = array(
'mystuff/alcon.doc.t' => 'mystuff/alcon.doc',
'mystuff/alcon.xls.t' => 'mystuff/alcon.xls',
) // files to rename
if ($obj->create($files)) {
echo 'Created successfully!';
} else {
echo 'Error in file creation';
}

FileIFrameField with Parsing

I'm using SilverStripe 2.4.7 and I want to add a method that parses the file which I have just uploaded with FileIFrameField. The thing that has me stumped is where to put this. I was thinking of the onAfterWrite method but the file only gets uploaded after the rest of the fields have been saved for the first time so I'm not sure this would work.
My question is: What is the best practice for this kind of thing?
Edit
I have this line of code where $filename is the path to my uploaded file but I keep getting a "no such file or directory error". I have even tried hardcoding in the filepath but get the same error.
$fh = fopen($filename, 'r');
the best way to parse a new file would be to hook into the uploadfield save method, for the FileIframeField you can do that by sub classing it and overwriting save()
(in SilverStripe 3 there is a new class called UploadField, in UploadField you would need to overwrite UploadField->upload(SS_HTTPRequest $request), and the file there would be accesable like this: $tmpfile = $request->postVar($this->getName()); )
below, and example on how to do it in FileIframeField:
class myFileIFrameField extends FileIFrameField {
public function save($data, $form) {
if (
!isset($data['FileSource'])
|| ($data['FileSource'] == 'new' && (!isset($_FILES['Upload']) || !$_FILES['Upload']))
|| ($data['FileSource'] == 'existing' && (!isset($data['ExistingFile']) || !$data['ExistingFile']))
) {
$form->sessionMessage(_t('FileIFrameField.NOSOURCE', 'Please select a source file to attach'), 'required');
Director::redirectBack();
return;
}
$fileContent = false;
if($data['FileSource'] == 'new') {
$fileContent = file_get_contents($_FILES['Upload']['tmp_name']);
}
elseif($data['FileSource'] == 'existing') {
$fileObject = DataObject::get_by_id('File', $data['ExistingFile']);
$fileContent = file_get_contents($fileObject->getFullPath());
}
if ($fileContent) {
// parse the $fileContent here
}
// if you want to still save the file into a relation,
//meaning if you want to have the actually FileIframeField behaviour still in tact then call
return parent::save($data, $form);
// other wise, if you do not want to save the relation and you don't want to save the file to the server
// thenn do NOT call parent::save, just do:
// Director::redirectBack();
}
}

FedexDC PHP Label Script - Need To Save But Not Display PNG Image - FEDEX Direct Connect class

I'm using the fedexdc class to generate a shipping label for orders. The problem is that when I run the function on my application's page, it outputs all of the binary mess from the image that is create. I really just need it to save on the server (which it does) and not display on the page so that i can access it when I need to. Here's the function in the fedexdc class file. Any ideas on how I can do this?
function label($label_file=false) {
$this->httpLabel = $this->rHash[$this->image_key];
if ($this->httpLabel = preg_replace('/%([0-9][0-9])/e', "chr(hexdec($1))", $this->httpLabel)) {
$this->debug('separate binary image data');
$this->debug('decoded binary label data');
}
if ($label_file) {
$this->debug('label: trying to write out label to '. $label_file);
$FH = fopen ($label_file, "w+b");
if (!fwrite($FH, $this->httpLabel)) {
$this->setError("Can't write to file $label_file");
return false;
}
fclose($FH);
} else {
return $this->httpLabel;
}
}

displaying blob images - symfony

I have blob data in my database and they are images that I want to display as a basic gallery.
I have a method that I have written to display the images, but I'm getting an error, saying that it is a string, rather than blob data being returned:
public function getFilenamePath()
{
$file_src = false;
if (null !== $fp = $this->getFilename())
{
$file = stream_get_contents($fp);
$file_src = '/uploads/gallery/'.$this->getId().'.jpg';
}
return $file_src;
}
where getFilename() is my blob column.
action:
public function executeSingle(sfWebRequest $request)
{
$application_id = $this->getRequestParameter('id');
$c = new Criteria();
$c->addJoin(GalleryPeer::APPLICATION_ID, ApplicationPeer::ID);
$c->addJoin(GalleryImagePeer::GALLERY_ID, GalleryPeer::ID);
$c->add(GalleryPeer::APPLICATION_ID, $application_id);
$this->galleries = GalleryImagePeer::doSelect ( $c );
}
template:
foreach($galleries as $gallery)
{
$path = $gallery->getFilenamePath();
if($path)
{
echo '<img src="'.$path.'" />';
}
}
The error I get is that stream_get_contents seems to be returning a string.
Is there anyway, I can get the blob data, or rather than use a model method, use an action to return all the images attached to the application?
Thanks
If you store images in the database, you have (basically) two options to show them on the client:
First solution: Get file content and encode it with base64 encoding. You can find a working example here:
http://www.php.net/manual/en/function.base64-encode.php#99842
This method is not the best as if you do it like that, the client won't be able to cache these images, that means more traffic, more processing time, more database connection, slower page loading etc.
Second solution: You create an image loading action in Symfony. The routing is like:
mapimage:
url: /myimage/:image_id.png
param: { module: myimagemodul, action: myimageaction }
You have to create a controller action myimageaction and there you can get the image ID like
$request->getParameter('image_id');
And get the blob data from the database and return it as binary with specific http headers. You can find working examples with simple Googleing, one example:
$this->image = ImagePeer::retrieveByPk ($request->getParameter('image_id'));
$response = $this->getResponse();
$response->clearHttpHeaders();
$response->setContentType ($this->image->getMimeType());
$response->setHttpHeader ('Content-Disposition', 'inline;filename='.$filename);
$content = $this->image->getData();
$response->setContent (stream_get_contents ($content));
$this->setLayout (false);
return sfView::NONE;
So in the template you can do like:
<img src='<?= url_for ('route_to_action_above', array ('image_id' => $image->getId()) ?>'/>
I have found this one at
http://forum.symfony-project.org/viewtopic.php?f=22&t=31207#p109705
This code doesn't make any sense.
Why do you feed binary(read string) data from ->getFilename() to stream_get_contents() which operates ONLY on resource data type? Of course it will complain.
Outputing blob to a browser is as simple as:
$this->getResponse->setContentType('image/jpeg');
echo $data->getFilename(); // assuming filename column is your blob column
try switching your getFilenamePath function to this.
public function getFilenamePath() {
$file_src = '/uploads/gallery/'.$this->getId().'.jpg';
if (file_exists($file_src ) {
return $file_src;
} else {
return false;
}
}
$profile_picture = base64_encode(stream_get_contents($image->getContent()));
echo '<img src="data:image/jpeg;base64,'.$profile_picture.'" />';

Categories