Drupal 6 Programmatically adding an image to a FileField - php

How do I programmatically add an image to a file field? I have an url/filepath of an image that I wish to upload. I have tried the following:
$newNode->field_profile_image[0]['value'] = 'http://www.mysite.com/default.gif';
But it does not seem to work.
I have also tried:
$newNode->field_profile_image[0]['value'] = 'sites/default/files/default.gif';
The file does not need to be external to the webiste. I am happy to have it anywhere on the site in question.

You're probably going to have to use hook_nodeapi to set this correctly. You're going to want to modify it under the "Insert" operation. Make sure that you resave the node after you've added the required fields.
Drupal wants to map the image to an entry in the file table, so simply setting the URL will not work. First off, if it's a remote file, you can use the function listed in the Brightcove module on line 176, brightcove_remote_image, to grab the image and move it into your local directory.
Once the remote image is moved into place, you need to save it into the files table and then properly configure the node's property. I've done it in this method:
////// in NodeAPI /////
case "insert":
$node->field_image[0] = _mymod_create_filearray($image_url);
node_save($node);
This writes the files record, and then returns a properly formatted image array.
///// mymod_create_filearray /////
function _mymod_create_filearray($remote_url){
if ($file_temp = brightcove_remote_image($remote_url)) {
$file = new stdClass();
$file->filename = basename($file_temp);
$file->filepath = $file_temp;
$file->filemime = file_get_mimetype($file_temp);
$file->filesize = filesize($file_temp);
$file->uid = $uid;
$file->status = FILE_STATUS_PERMANENT;
$file->timestamp = time();
drupal_write_record('files', $file);
$file = array(
'fid' => $file->fid,
'title' => basename($file->filename),
'filename' => $file->filename,
'filepath' => $file->filepath,
'filesize' => $file->filesize,
'mimetype' => $mime,
'description' => basename($file->filename),
'list' => 1,
);
return $file;
}
else {
return array();
}
}
And that should do it. Let me know if you have any questions.

Check out my Answer to a similar question from a while ago, where I describe how we did pretty much exactly what you need (if I understood the problem correctly).
The main point is to use the field_file_save_file() function from the filefield module for attaching a file (during hook_nodeapi, on operation presave), which will do most of the work for you (more or less what jacobangel's '_mymod_create_filearray()' tries to do, but more tuned to filefields needs, including validation).
This assumes that the file already exists on the servers filesystem somewhere (usually in /tmp), and will correctly 'import' it into Drupal, with corresponding entries in the files table, etc. If you want to import files from remote URLs, you'll need to add the additional step of fetching them as a separate task/functionality first.
As mentioned in the answer linked above, I ended up using the code from the Remote File module as an example for a custom implementation, as we needed some project specific additions - maybe you can use it more directly for your purposes.

using nodeapi you should be able to set the value like you are trying to in the code example, but only or local images. You will most likely need to have the images in the "files" folder in your drupal install, but if that is set up everything else should work without a hitch. When using the nodeapi all the things that would normally happen when you save a node using a form would happen, such as updating the files table etc.
If you wanted to pull the image from the remote site using a module like feeds make it possible to pull the remote images, and create nodes. Depending on your use case you could either use it, or take a look at how it pulls the images and maps them to local files.

What you try will not work. Drupal offers no way to handle remote files, without the use for a module. AFAIK there is no module that offers an API to upload remote files trough.

Here is a quick example taken from one of my projects.
$node = new stdClass;
$node->title = 'Example Callout';
$node->type = 'wn_hp_callout';
// Search examples directory to attach some images.
$callouts_dir = drupal_get_path('module', 'wn_hp_callout').'/imgs/examples/';
$callout_imgs = glob($callouts_dir.'*.{jpg,jpeg,png,gif}',GLOB_BRACE);
// Now add the images and provide imagefield extended additional text.
foreach($callout_imgs as $img) {
$img_info = pathinfo($img);
$field = field_file_save_file($img, array(), file_directory_path() .'/example_callouts/');
if( !isset($field['data']) ) {
$field['data'] = array();
}
$field['data']['title'] = ucwords(str_replace('_',' ',$img_info['filename']));
$field['data']['alt'] = 'This is alt text.';
$node->field_wn_hp_callout_image[] = $field;
}
$node = node_submit($node);
node_save($node);

Related

What is the best way to get the parameters in PHP?

I will completely clarify my question, sorry to everybody.
I have code writed in files from a website that now is not working, the html code is on pages with php extension, in a folder of a Virtual Host in my PC using Wampserever. C:\wamp\1VH\PRU1, when the site was online there was a folder where was a file called image.php. This file was called from other pages inside the site like this: (a little code of a file, C:\wamp\1VH\PRU1\example.php)
"<div><img src="https://www.example.com/img/image.php?f=images&folder=foods&type=salads&desc=green&dim=50&id=23" alt="green salad 23"></div>"
And the result was that the images was showed correctly.
Now, like i have this proyect in local, and i HAVE NOT the code of that image.php file i must to write it myself, this way the images will be showed the same way that when the site was online.
When the site was online and i open a image returned by that image.php file the URL was, following the example, https://example.com/images/foods/salads/green_50/23.png.
Now how the site is only local and i have not that image.php file writed because i'm bot sure how to write it, the images obviously are not showed.
In C:\wamp\1VH\PRU1\example.php the code of files was changed deleting "https://www.example.com/img/image.php?" for a local path "img/image.php?".
And in the same folder there is anothers: "img" folder (here must be allocated the image.php file), and "images" folder, inside it /foods/salads/green_50/23.png, 24.png.25.png..............
So i have exactly the same folder architecture that the online site and i changed the code that i could only, for example replacing with Jquery "https://www.example.com/img/image.php?" for "img/image.php?" but wich i can not do is replace all the code after the image.php file to obtain a image file.
So i think that the easiest way to can obtain the images normally is creating that IMAGE.PHP file that i have not here in my virtual host.
I'd like to know how to obtain the parameters and return the correct URL in the image,php file.
The image of the DIV EXAMPLE must be C:/wamp/1VH/PRU1/images/foods/salads/green_50/23.png
I have in my PC the correct folders and the images, i only need to write the image.php file.
Note that there are "&" and i must to unite the values of "desc=green&dim=50&" being the result: green_50 (a folder in my PC).
TVM.
You probably want something like this.
image.php
$id = intval($_GET['id']);
echo '<div><img src="images/foods/salads/green_50/'.$id.'.png" alt="green salad '.$id.'"></div>';
Then you would call this page
www.example.com/image.php?id=23
So you can see here in the url we have id=23 in the query part of the url. And we access this in PHP using $_GET['id']. Pretty simple. In this case it equals 23 if it was id=52 it would be that number instead.
Now the intval part is very important for security reasons you should never put user input directly into file paths. I won't get into the details of Directory Transversal attacks. But if you just allow anything in there that's what you would be vulnerable to. It's often overlooked, so you wouldn't be the first.
https://en.wikipedia.org/wiki/Directory_traversal_attack
Now granted the Server should have user permissions setup properly, but I say why gamble when we can be safe with 1 line of code.
This should get you started. For the rest of them I would setup a white list like this:
For
folder=foods
You would make an array with the permissible values,
$allowedFolders = [
'food',
'clothes'
'kids'
];
etc...
Then you would check it like this
///set a default
$folder = '';
if(!empty($_GET['folder'])){
if(in_array($_GET['folder'], $allowedFolders)){
$folder = $_GET['folder'].'/';
}else{
throw new Exception('Invalid value for "folder"');
}
}
etc...
Then at the end you would stitch all the "cleaned" values together. As I said before a lot of people simply neglect this and just put the stuff right in the path. But, it's not the right way to do it.
Anyway hope that helps.
You essentially just need to parse the $_GET parameters, then do a few checks that the file is found, a real image and then just serve the file by setting the appropriate content type header and then outputting the files contents.
This should do the trick:
<?php
// define expected GET parameters
$params = ['f', 'folder', 'type', 'desc', 'dim', 'id'];
// loop over parameters in order to build path: /imagenes/foods/salads/green_50/23.png
$path = null;
foreach ($params as $key => $param) {
if (isset($_GET[$param])) {
$path .= ($param == 'dim' ? '_' : '/').basename($_GET[$param]);
unset($params[$key]);
}
}
$path .= '.png';
// check all params were passed
if (!empty($params)) {
die('Invalid request');
}
// check file exists
if (!file_exists($path)) {
die('File does not exist');
}
// check file is image
if (!getimagesize($path)) {
die('Invalid image');
}
// all good serve file
header("Content-Type: image/png");
header('Content-Length: '.filesize($path));
readfile($path);
https://3v4l.org/tTALQ
use $_GET[];
<?php
$yourParam = $_GET['param_name'];
?>
I can obtain the values of parameters in the image.php file tis way:
<?php
$f = $_GET['f'];
$folder = $_GET['folder'];
$type = $_GET['type'];
$desc = $_GET['desc'];
$dim = $_GET['dim'];
$id = $_GET['id'];
?>
But what must i do for the image:
C:/wamp/1VH/PRU1/images/foods/salads/green_50/23.png
can be showed correctly in the DIV with IMG SRC atribute?

Create .tar.gz file using PHP

The project I am working on requires creating .tar.gz archives and feeding it to an external service. This external service works only with .tar.gz so another type archive is out of question. The server where the code I am working on will execute does not allow access to system calls. So system, exec, backticks etc. are no bueno. Which means I have to rely on pure PHP implementation to create .tar.gz files.
Having done a bit of research, it seems that PharData will be helpful to achieve the result. However I have hit a wall with it and need some guidance.
Consider the following folder layout:
parent folder
- child folder 1
- child folder 2
- file1
- file2
I am using the below code snippet to create the .tar.gz archive which does the trick but there's a minor issue with the end result, it doesn't contain the parent folder, but everything within it.
$pd = new PharData('archive.tar');
$dir = realpath("parent-folder");
$pd->buildFromDirectory($dir);
$pd->compress(Phar::GZ);
unset( $pd );
unlink('archive.tar');
When the archive is created it must contain the exact folder layout mentioned above. Using the above mentioned code snippet, the archive contains everything except the parent folder which is a deal breaker for the external service:
- child folder 1
- child folder 2
- file1
- file2
The description of buildFromDirectory does mention the following so it not containing the parent folder in the archive is understandable:
Construct a tar/zip archive from the files within a directory.
I have also tried using buildFromIterator but the end result with it also the same, i.e the parent folder isn't included in the archive. I was able to get the desired result using addFile but this is painfully slow.
Having done a bit more research I found the following library : https://github.com/alchemy-fr/Zippy . But this requires composer support which isn't available on the server. I'd appreciate if someone could guide me in achieving the end result. I am also open to using some other methods or library so long as its pure PHP implementation and doesn't require any external dependencies. Not sure if it helps but the server where the code will get executed has PHP 5.6
Use the parent of "parent-folder" as the base for Phar::buildFromDirectory() and use its second parameter to limit the results only to "parent-folder", e.g.:
$parent = dirname("parent-folder");
$pd->buildFromDirectory($parent, '#^'.preg_quote("$parent/parent-folder/", "#").'#');
$pd->compress(Phar::GZ);
I ended up having to do this, and as this question is the first result on google for the problem here's the optimal way to do this, without using a regexp (which does not scale well if you want to extract one directory from a directory that contains many others).
function buildFiles($folder, $dir, $retarr = []) {
$i = new DirectoryIterator("$folder/$dir");
foreach ($i as $d) {
if ($d->isDot()) {
continue;
}
if ($d->isDir()) {
$newdir = "$dir/" . basename($d->getPathname());
$retarr = buildFiles($folder, $newdir, $retarr);
} else {
$dest = "$dir/" . $d->getFilename();
$retarr[$dest] = $d->getPathname();
}
}
return $retarr;
}
$out = "/tmp/file.tar";
$sourcedir = "/data/folder";
$subfolder = "folder2";
$p = new PharData($out);
$filemap = buildFiles($sourcedir, $subfolder);
$iterator = new ArrayIterator($filemap);
$p->buildFromIterator($iterator);
$p->compress(\Phar::GZ);
unlink($out); // $out.gz has been created, remove the original .tar
This allows you to pick /data/folder/folder2 from /data/folder, even if /data/folder contains several million OTHER folders. It then creates a tar.gz with the contents all being prepended with the folder name.

Uploaded files are getting deleted in Drupal?

I have to administer a Drupal Website, which I didn't set up and honestly, I haven't much experience with Drupal yet.
But I have a serious problem: If I upload a file (it's a PDF) not attached to a node, it will be deleted every few hours. Apparently, I need to indicate it as permanent manually from the file overview page.
Is there a way to set it as permanent automatically?
Hope you can help me! Thanks!
You need to set the status parameter on the file object then use file_save to save it:
// First obtain a file object, for example by file_load...
$file = file_load(10);
// Or as another example, the result of a file_save_upload...
$file = file_save_upload('upload', array(), 'public://', FILE_EXISTS_REPLACE);
// Now you can set the status
$file->status = FILE_STATUS_PERMANENT;
// And save the status.
file_save($file);

PHP methods for Implementing a pseudo cache system for files

This question is more about methodology than actual code - lines
I would like to know how to implement a pseudo caching (for lack of a better name) for FILES in php . I have tried to read some articles, but most of them refer to the internal caching system of PHP , and not to what I need which is a FILE cache.
I have several scenarios where I needed such a system applied :
Scenario 1 :
While accessing a post and clicking a link, all the post attachments are collected and added to a zip file for download.
Scenario 2 :
Accessing a post , the script will scan all the content , extract all links, download some matching images for each link (or dynamically prepare one) and then serve those to browser . (but not after checing expiration period ?? )
( Those example uses "post" and "attachment" because i use wordpress and it is wordpress terminology, both currently work for me fine, except they generate the file over and over again. )
My doubts regarding the two scenarios (especially No.2) - How do I prevent the script to do the operation EVERY time the page is accessed ? (in other words , if the file exists , just serve it without looping the whole creating operation again)
My first instinct was call the file with some distinctive (but not load - unique like uniqueid() ) name and then check if it is already on the server , but that presents several problems (like it can already exists as naming , but of another post ..) and also - that should be very resource intensive for a server with 20,000 images .
The second thing I thought was to somehow associate a meta data for those files, but then again, How to implement it ? How to knwo which link is of what image ??
Also, in a case where I check for the file existence on the server , how can I know if the file SHOULD be changed (and therefor recreated ) ?
Since I am refering to wordpress, I thought about storing those images as base64 from binary directly to the DB with the transien_API - but it feels quite clumsy.
To sum up the question . How to generate a file, but also know if it exists and call it directly when needed ?? does my only option is store the file-name in DB and associate it somehow with the post ?? that seems so non efficient ..
EDIT I
I decided to include some example code , as it can help people to understand my dilemma .
function o99_wbss_prepare_with_callback($content,$width='250'){
$content = preg_replace_callback( '/(http[s]?:[^\s]*)/i', 'o99_wbss_prepare_cb', $content );
return $content;
}
function o99_wbss_prepare_cb($match){
$url = $match[1];
$url = esc_url_raw( $url );//someone said not need ??
$url_name = parse_url($url);
$url_name = $url_name['host'];// get rid of http://..
$param = '660';
$url = 'http://somescript/' . urlencode($url) . '?w=' . $param ;
$uploads = wp_upload_dir();
//$uniqid = uniqid();
$img = $uploads['basedir'] . '/tmp/' . $url_name .'.jpg' ; // was with $uniqid...
if(! # file_get_contents($url)){
$url = 'path ' .$url. ' doesn"t exist or unreachable';
return $url;
} else {
$file = file_get_contents( $url );
}
// here I will need to make some chck if the file already was generated , and
// if so - just serve it ..
if ( $file) {
file_put_contents( $img, $file );
// Do some other operations on the file and prepare a new one ...
// this produces a NEW file in the wp-uploads folder with the same name...
unlink($img);
}
return $url;
}
For Scenario 1:
Wordpress stored all post attachments as posts in the posts table. When a post is accessed run a function either in a created plugin or your themes functions.php. Use the pre_get_posts hook check if you have already created the zip file with function file_exists() using a unique name for each zip archive you create, post ID or permalink would be a good idea. Although you would need to make sure there was no user specific content. You can use filemtime() to check the time the file was created and if it is still relevant. If zip file does not exist create it, pre_get_posts will pass the query object which has the the post ID, just grab all the post attachments using get_posts and the parent ID being set to the ID passed in the query object. The GUID field contains the URL for each attachment then just generate a zip archive using ZipArchive() following this tutorial at.
For Scenario 2:
If your wordpress templates are set up to use the wordpress functions then replace the attachment functions to return their url and map that to the new url you have the cached content. For example the_post_thumbnail() would go to wp_get_attachment_thumb_url() copy the file to your cache and use the cache url as output. If you wanted to cache the DOM for the page as well use ob_start(). Now just run a check at the start of the template using file_exists and filetime(), if both are valid read in the cached DOM instead of loading the page.

Using PHP to write to .swf files

I was wondering how to basically edit a .swf file using php, to change a single variable or to change more. How would I go about doing this? Is there a way to edit it without knowing machine code?
If there is an example of how to do this, where can I find it?
Thanks!
Or, if there is an easier way to go about doing this, please let me know!
take a look at libming
php documentation at http://docs.php.net/manual/en/book.ming.php
With Actionscript, it's very simple to load external data: XML and JSON are two standardized ways to do it, and both are easily generated by PHP. What exactly are you trying to do?
The question is old, but since it happens to coincide with what I've been working on, I figured I would put something together in case others find it useful. The solution works for AS3 only. It let you to change the values of instance variables and constants.
Suppose you have the following class:
package pl.krakow.rynek {
import flash.display.Sprite;
public class Advertisement extends Sprite {
private var title:String = 'Euro 2012 LIVE!';
/* ... */
}
}
You want the var title to be something else. The code for doing so is as follow:
<?php
require_once 'flaczki/classes.php';
// parse the SWF file, decoding only those tags needed by the injector
$input = fopen("input.swf", "rb");
$parser = new SWFParser;
$injector = new AS3ConstantInjector;
$swfFile = $parser->parse($input, $injector->getRequiredTags());
$classConstants = array(
'pl.krakow.rynek.Advertisement' => array(
'title' => 'Free Beer!'
)
);
// inject the values and reassemble the file
$injector->inject($swfFile, $classConstants);
$output = fopen($outPath, "wb");
$assembler = new SWFAssembler;
$assembler->assemble("output.swf", $swfFile);
?>
The code should be self-explanatory. The SWF file is first parsed, modifications are made, and the in-memory structure is saved to file. AS3ConstantInjector.inject() expects as the second argument an array of arrays keyed by the qualified names of the classes you wish to modify. The arrays themselves hold the new values for each class, with the key as the variable/constant name.
To see The variables in a SWF file, use AS3ConstantExtractor:
<?php
require_once 'flaczki/classes.php';
$input = fopen("button.swf", "rb");
$parser = new SWFParser;
$extractor = new AS3ConstantExtractor;
$swfFile = $parser->parse($input, $extractor->getRequiredTags());
$classConstants = $extractor->extract($swfFile);
print_r($classConstants);
?>
The Flaczki classes can be downloaded at http://code.google.com/p/flaczki/downloads/list
You can find out more about the Flaczki framework at the project development blog at http://flaczkojad.blogspot.com/
check out the SWF-library in php
Instead of thinking how to generate swf files, do the opposite and let the internal behavior depend on external logic in a php script. This way you never need to (re)compile your swf.

Categories