I have an instance of a template on PHPWord. Is it possible to replace or add an image? Something like a setImageValue?
$phpWord = new \PhpOffice\PhpWord\Template('a.docx');
$phpWord->setImageValue('IMAGE_PLACEHOLDER', 'a.jpg');
$phpWord->saveAs('b.docx');
Is something like this possible?
Following code is the updated version of the one from TotPeRo (thanks again for your code!), for last phpOffice (0.11) that has evolved a little
/**
* Set a new image
*
* #param string $search
* #param string $replace
*/
public function setImageValue($search, $replace)
{
// Sanity check
if (!file_exists($replace))
{
return;
}
// Delete current image
$this->zipClass->deleteName('word/media/' . $search);
// Add a new one
$this->zipClass->addFile($replace, 'word/media/' . $search);
}
Can be called with:
$document->setImageValue('image1.jpg', 'my_image.jpg');
If you want to add, remove or replace image in template.docx you can add this to your TemplateProcessor.php file, (it works for me with PhpWord 0.14.0 version):
1.
// add this in the class
protected $_rels;
protected $_types;
public function __construct($documentTemplate){
// add this line to this function
$this->_countRels=100;
}
2.
public function save()
{
//add this snippet to this function after $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart);
if($this->_rels!=""){
$this->zipClass->addFromString('word/_rels/document.xml.rels', $this->_rels);
}
if($this->_types!=""){
$this->zipClass->addFromString('[Content_Types].xml', $this->_types);
}
}
3. Add this function too:
public function setImg( $strKey, $img){
$strKey = '${'.$strKey.'}';
$relationTmpl = '<Relationship Id="RID" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/IMG"/>';
$imgTmpl = '<w:pict><v:shape type="#_x0000_t75" style="width:WIDpx;height:HEIpx"><v:imagedata r:id="RID" o:title=""/></v:shape></w:pict>';
$toAdd = $toAddImg = $toAddType = '';
$aSearch = array('RID', 'IMG');
$aSearchType = array('IMG', 'EXT');
$countrels=$this->_countRels++;
//I'm work for jpg files, if you are working with other images types -> Write conditions here
$imgExt = 'jpg';
$imgName = 'img' . $countrels . '.' . $imgExt;
$this->zipClass->deleteName('word/media/' . $imgName);
$this->zipClass->addFile($img['src'], 'word/media/' . $imgName);
$typeTmpl = '<Override PartName="/word/media/'.$imgName.'" ContentType="image/EXT"/>';
$rid = 'rId' . $countrels;
$countrels++;
list($w,$h) = getimagesize($img['src']);
if(isset($img['swh'])) //Image proportionally larger side
{
if($w<=$h)
{
$ht=(int)$img['swh'];
$ot=$w/$h;
$wh=(int)$img['swh']*$ot;
$wh=round($wh);
}
if($w>=$h)
{
$wh=(int)$img['swh'];
$ot=$h/$w;
$ht=(int)$img['swh']*$ot;
$ht=round($ht);
}
$w=$wh;
$h=$ht;
}
if(isset($img['size']))
{
$w = $img['size'][0];
$h = $img['size'][1];
}
$toAddImg .= str_replace(array('RID', 'WID', 'HEI'), array($rid, $w, $h), $imgTmpl) ;
if(isset($img['dataImg']))
{
$toAddImg.='<w:br/><w:t>'.$this->limpiarString($img['dataImg']).'</w:t><w:br/>';
}
$aReplace = array($imgName, $imgExt);
$toAddType .= str_replace($aSearchType, $aReplace, $typeTmpl) ;
$aReplace = array($rid, $imgName);
$toAdd .= str_replace($aSearch, $aReplace, $relationTmpl);
$this->tempDocumentMainPart=str_replace('<w:t>' . $strKey . '</w:t>', $toAddImg, $this->tempDocumentMainPart);
//print $this->tempDocumentMainPart;
if($this->_rels=="")
{
$this->_rels=$this->zipClass->getFromName('word/_rels/document.xml.rels');
$this->_types=$this->zipClass->getFromName('[Content_Types].xml');
}
$this->_types = str_replace('</Types>', $toAddType, $this->_types) . '</Types>';
$this->_rels = str_replace('</Relationships>', $toAdd, $this->_rels) . '</Relationships>';
}
4. And this:
function limpiarString($str) {
return str_replace(
array('&', '<', '>', "\n"),
array('&', '<', '>', "\n" . '<w:br/>'),
$str
);
}
5. How to use:
//open your template
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('files/template.docx');
//add image to selector
$templateProcessor->setImg('selector',array('src' => 'image.jpg','swh'=>'200', 'size'=>array(0=>$width, 1=>$height));
// You can also clone row if you need
//$templateProcessor->cloneRow('NAME_IN_TEMPLATE', NUMBER_OF_TABLE_RECORDS);
$templateProcessor->cloneRow('SELECTOR', 4);
//save
header("Content-Disposition: attachment; filename='helloWord.docx'");
$templateProcessor->saveAs('php://output');
his is pretty much untested. but this is working for me (although mine is slightly different):
add the following function to PHPWord/Template.php :
public function save_image($id,$filepath,&$document=null) {
if(file_exists($filepath))
{
$this->_objZip->deleteName('word/media/'.$id);
$this->_objZip->addFile ($filepath,'word/media/'.$id);
//$document->setValue($id.'::width', "300px");
//$document->setValue($id.'::height', "300px");
}
}
create a document with an actual image to be used as a place holder (this solution don't allow setting the with & height of the image or multiple extensions).
unzip the the documnt and check for the file name in word/media folder. use this file name as the $id for the save_image function.
you can now use:
$document->save_image('image1',$image_path,$document);
I created some functions to extend Jerome's solution. The problem was that in order to change the picture we had to know it's reference name in the docx file. This could be difficult to find out for an average user (you have to "unZip" the docx, and find your picture manually).
My solution makes it possible to reference pictures by alt text (it needs to be in usual format: ${abc} )
so one doesn't have to know how word names the placeholder picture, the variable is enough.
Here's a link about how to add alt texts: http://accessproject.colostate.edu/udl/modules/word/tut_alt_text.php?display=pg_2
I only modified TemplateProcessor.php
First add this to the class:
/**
* Content of document rels (in XML format) of the temporary document.
*
* #var string
*/
private $temporaryDocumentRels;
The constructor function (public function __construct($documentTemplate)) needs to be extended at the end. Add this:
$this->temporaryDocumentRels = $this->zipClass->getFromName('word/_rels/document.xml.rels');
Now you can read stuff from document.xml.rels by using $this->temporaryDocumentRels
Keep Jerome's code:
/**
* Set a new image
*
* #param string $search
* #param string $replace
*/
public function setImageValue($search, $replace){
// Sanity check
if (!file_exists($replace))
{
return;
}
// Delete current image
$this->zipClass->deleteName('word/media/' . $search);
// Add a new one
$this->zipClass->addFile($replace, 'word/media/' . $search);
}
This function returns with the rId of the image you labeled:
/**
* Search for the labeled image's rId
*
* #param string $search
*/
public function seachImagerId($search){
if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') {
$search = '${' . $search . '}';
}
$tagPos = strpos($this->temporaryDocumentMainPart, $search);
$rIdStart = strpos($this->temporaryDocumentMainPart, 'r:embed="',$tagPos)+9;
$rId=strstr(substr($this->temporaryDocumentMainPart, $rIdStart),'"', true);
return $rId;
}
And this returns the images filename, if you know it's rId:
/**
* Get img filename with it's rId
*
* #param string $rId
*/
public function getImgFileName($rId){
$tagPos = strpos($this->temporaryDocumentRels, $rId);
$fileNameStart = strpos($this->temporaryDocumentRels, 'Target="media/',$tagPos)+14;
$fileName=strstr(substr($this->temporaryDocumentRels, $fileNameStart),'"', true);
return $fileName;
}
The modifications in TemplateProcessor.php are done.
Now you can replace the image by calling this:
$templateProcessor->setImageValue($templateProcessor->getImgFileName($templateProcessor->seachImagerId("abc")),$replace);
You can also create a functionin TemplateProcessor.php that calls it like:
public function setImageValueAlt($searchAlt, $replace){
$this->setImageValue($this->getImgFileName($this->seachImagerId($searchAlt)),$replace);
}
I was looking for a solution to add an image. I read a lot of articles, I only found suitable solutions for older versions. Changing and finalized the decision to get the code.
Let us proceed to change the file TemplateProcessor.php
public function __construct($documentTemplate)
{
//add to this function
$this->_countRels=100; //start id for relationship between image and document.xml
}
public function save()
{
//add to this function after $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart);
if($this->_rels!="")
{
$this->zipClass->addFromString('word/_rels/document.xml.rels', $this->_rels);
}
if($this->_types!="")
{
$this->zipClass->addFromString('[Content_Types].xml', $this->_types);
}
}
//add function
public function setImg( $strKey, $img){
$strKey = '${'.$strKey.'}';
$relationTmpl = '<Relationship Id="RID" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/IMG"/>';
$imgTmpl = '<w:pict><v:shape type="#_x0000_t75" style="width:WIDpx;height:HEIpx"><v:imagedata r:id="RID" o:title=""/></v:shape></w:pict>';
$toAdd = $toAddImg = $toAddType = '';
$aSearch = array('RID', 'IMG');
$aSearchType = array('IMG', 'EXT');
$countrels=$this->_countRels++;
//I'm work for jpg files, if you are working with other images types -> Write conditions here
$imgExt = 'jpg';
$imgName = 'img' . $countrels . '.' . $imgExt;
$this->zipClass->deleteName('word/media/' . $imgName);
$this->zipClass->addFile($img['src'], 'word/media/' . $imgName);
$typeTmpl = '<Override PartName="/word/media/'.$imgName.'" ContentType="image/EXT"/>';
$rid = 'rId' . $countrels;
$countrels++;
list($w,$h) = getimagesize($img['src']);
if(isset($img['swh'])) //Image proportionally larger side
{
if($w<=$h)
{
$ht=(int)$img['swh'];
$ot=$w/$h;
$wh=(int)$img['swh']*$ot;
$wh=round($wh);
}
if($w>=$h)
{
$wh=(int)$img['swh'];
$ot=$h/$w;
$ht=(int)$img['swh']*$ot;
$ht=round($ht);
}
$w=$wh;
$h=$ht;
}
if(isset($img['size']))
{
$w = $img['size'][0];
$h = $img['size'][1];
}
$toAddImg .= str_replace(array('RID', 'WID', 'HEI'), array($rid, $w, $h), $imgTmpl) ;
if(isset($img['dataImg']))
{
$toAddImg.='<w:br/><w:t>'.$this->limpiarString($img['dataImg']).'</w:t><w:br/>';
}
$aReplace = array($imgName, $imgExt);
$toAddType .= str_replace($aSearchType, $aReplace, $typeTmpl) ;
$aReplace = array($rid, $imgName);
$toAdd .= str_replace($aSearch, $aReplace, $relationTmpl);
$this->tempDocumentMainPart=str_replace('<w:t>' . $strKey . '</w:t>', $toAddImg, $this->tempDocumentMainPart);
//print $this->tempDocumentMainPart;
if($this->_rels=="")
{
$this->_rels=$this->zipClass->getFromName('word/_rels/document.xml.rels');
$this->_types=$this->zipClass->getFromName('[Content_Types].xml');
}
$this->_types = str_replace('</Types>', $toAddType, $this->_types) . '</Types>';
$this->_rels = str_replace('</Relationships>', $toAdd, $this->_rels) . '</Relationships>';
}
//add function
function limpiarString($str) {
return str_replace(
array('&', '<', '>', "\n"),
array('&', '<', '>', "\n" . '<w:br/>'),
$str
);
}
//HOW TO USE???
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('templ.docx');
//static zone
$templateProcessor->setValue('date', htmlspecialchars(date('d.m.Y G:i:s')));
//$templateProcessor->cloneRow('NAME_IN_TEMPLATE', NUMBER_OF_TABLE_RECORDS);
$templateProcessor->cloneRow('AVTOR', 3);
//variant 1
//dynamic zone
$templateProcessor->setValue('AVTOR#1', htmlspecialchars('Garry'));
$templateProcessor->setValue('NAME#1', htmlspecialchars('Black Horse'));
$templateProcessor->setValue('SIZES#1', htmlspecialchars('100x300'));
/*$img = array(
'src' => 'image.jpg',//path
'swh'=>'350',//Image proportionally larger side
'size'=>array(580, 280)
);*/
$templateProcessor->setImg('IMGD#1',array('src' => 'image.jpg','swh'=>'250'));
$templateProcessor->setValue('AVTOR#2', htmlspecialchars('Barry'));
$templateProcessor->setValue('NAME#2', htmlspecialchars('White Horse'));
$templateProcessor->setValue('SIZES#2', htmlspecialchars('200x500'));
$templateProcessor->setImg('IMGD#2',array('src' => 'image2.jpg','swh'=>'250'));
$templateProcessor->setValue('AVTOR#3', htmlspecialchars('Backer'));
$templateProcessor->setValue('NAME#3', htmlspecialchars('Another Side'));
$templateProcessor->setValue('SIZES#3', htmlspecialchars('120x430'));
$templateProcessor->setImg('IMGD#3',array('src' => 'image3.jpg','swh'=>'250'));
//variant 2
$templateProcessor->cloneRow('AVTOR', count($output['ID']));
for($i=0;$i<count($output['ID']);$i++)
{
$templateProcessor->setValue('AVTOR'.'#'.($i+1), htmlspecialchars($output['AVTOR'][$i]));
$templateProcessor->setValue('NAME'.'#'.($i+1), htmlspecialchars($output['PNAM'][$i]));
//GetImg($output['ID'][$i]) my function return image path
$templateProcessor->setImg('IMGD'.'#'.($i+1), array('src'=>GetImg($output['ID'][$i]),'swh'=>'250'));
}
//Save
$templateProcessor->saveAs('testTemplate.docx');
modify the name of the *.docx to *.zip
open the zip folder
view the "word/media/****" the imgage name is to replace name
for setImageValue($search, $replace)
$search must be equls $replace OR use $this->zipClass->renameName ($replace , $search);
Just a note for anyone reading this in 2020 and later, PhpWord now has setImageValue() method, docs can be found here: https://phpword.readthedocs.io/en/latest/templates-processing.html#setimagevalue
If you open your .docx template as a .zip archive, you will find all media files in the word/media/ folder, then you need to find your placeholder image and replace it. I did it in the following way:
$this->templateProcessor->zip()->pclzipAddFile($imageUrl, 'word/media/image1.png');
In this case, the image styles remain the same as in the template.
Thanks to all the marvellous answers in this post, finally I had came out with my solution of replacing image in phpword 1.0.0 version and would like to share my code here : (Most thanks goes to #csanády-bálint for the detail coding)
My issue,
how can I know the rId of the image?
how can I know image is jpg or png or others?
I found out the image will begin with naming pattern of image1, image2, image3, and so on, therefore, I modified the concept to instead of getting the image by rId, I switch to get the image by name and can just ignore the image extension as well at the same time.
I only modified TemplateProcessor.php
First add this to the class :
/**
* Content of document rels (in XML format) of the temporary document.
*
* #var string
*/
private $temporaryDocumentRels;
Next, add following to the end of the constructor function (public function __construct($documentTemplate))
$this->temporaryDocumentRels = $this->zipClass->getFromName($this->getRelationsName($this->getMainPartName()));
And finally, just add following new function to TemplaceProcessor.php
/**
* Replace image by name
*
* #param string $search
* #param mixed $replace
*/
public function replaceImage($search, $replace): void
{
$fileNameStart = strpos($this->temporaryDocumentRels, $search);
$fileName = strstr(substr($this->temporaryDocumentRels, $fileNameStart), '"', true);
$this->zipClass->addFromString("word/media/" . $fileName, $replace);
}
Last but not least, the usage:
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('files/template.docx');
// image in file, eg. image1, image2, and so on
$search = 'image1';
// replacement image, can be from global http as well,
// like https://legacy.gscdn.nl/archives/images/HassVivaCatFight.jpg
$replace = 'replacement_image.png';
$fileGetContents = file_get_contents($replace);
if ($fileGetContents !== false) {
$templateProcessor->replaceImage($search, $fileGetContents);
}
The image replace is done by following code :
$this->zipClass->addFromString("word/media/" . $fileName, $replace);
where I found the code in the description of the zip() class (public function zip())
To replace an image:
$templateProcessor->zip()->AddFromString("word/media/image1.jpg",
file_get_contents($file));
Hope it helps!
Related
I'm working in WordPress with Contact Form 7. I'm dynamically creating a Word Document based on the users submitted data, and I want to attach that file to the e-mail that the user is sent from Contact Form 7.
To confirm, the file is created and saved in the correct location. My issue is definitely with attaching it to the e-mail from CF7.
I have the following code at the moment:
add_action('wpcf7_before_send_mail', 'cv_word_doc');
function cv_word_doc($WPCF7_ContactForm) {
// Check we're on the CV Writer (212)
if ( $WPCF7_ContactForm->id() === 212 ) {
//Get current form
$wpcf7 = WPCF7_ContactForm::get_current();
// get current SUBMISSION instance
$submission = WPCF7_Submission::get_instance();
if ($submission) {
// get submission data
$data = $submission->get_posted_data();
// nothing's here... do nothing...
if (empty($data))
return;
// collect info to add to word doc, removed for brevity...
// setup upload directory and name the file
$upload_dir = wp_upload_dir();
$upload_dir = $upload_dir['basedir'] . '/cv/';
$fileName = 'cv-' . str_replace(' ', '-', strtolower($firstName)) . '-' . str_replace(' ', '-', strtolower($lastName)) .'-'. time() .'.docx';
// PHPWord stuff, removed for brevity...
// save the doc
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save($upload_dir . $fileName);
// add upload to e-mail
$submission->add_uploaded_file('docx', $upload_dir . $fileName);
// carry on with cf7
return $wpcf7;
}
}
}
Everything works up until $submission->add_uploaded_file('docx', $upload_dir . $fileName);.
There's not much documentation about, but I have read that I need to include something similar to:
add_filter( 'wpcf7_mail_components', 'mycustom_wpcf7_mail_components' );
function mycustom_wpcf7_mail_components( $components ) {
$components['attachments'][] = 'full path of your PDF file';
return $components;
}
(source: https://wordpress.stackexchange.com/questions/239579/attaching-a-pdf-to-contact-form-7-e-mail-via-functions-php)
In order to get the attachment to show. However, I don't know how I can get the specific file that I need, as the file is unique to each submission and all of the variables will be in a separate function.
Fixed this issue.
I added:
// make file variable global
global $CV_file;
$CV_file = $upload_dir . $fileName;
after $submission->add_uploaded_file('docx', $upload_dir . $fileName);
Then seperate to the add_action, I used the filter and referenced the global var:
add_filter( 'wpcf7_mail_components', 'mycustom_wpcf7_mail_components' );
function mycustom_wpcf7_mail_components( $components ) {
global $CV_file;
$components['attachments'][] = $CV_file;
return $components;
}
Here is the working solution:
add_filter('wpcf7_mail_components', 'custom_wpcf7_mail_components');
function custom_wpcf7_mail_components($components)
{
//Get current form
$wpcf7 = WPCF7_ContactForm::get_current();
$attachment_file_path = '';
//check the relevant form id
if ($wpcf7->id == '30830') {
// get current SUBMISSION instance
$submission = WPCF7_Submission::get_instance();
if ($submission) {
// get submission data
$data = $submission->get_posted_data();
// setup upload directory
$upload_dir = wp_upload_dir();
if (isset($data['file_name']) && !empty($data['file_name'])) {
/*
* Form hidden attachment file name Ex: 'ProRail_NA_Gen5.pdf'
* You can hard-code the file name or set file name to hidden form field using JavaScript
*/
$file_name = $data['file_name'];
//get upload base dir path Ex: {path}/html/app/uploads
$base_dir = $upload_dir['basedir'];
//file uploaded folder
$file_dir = 'download';
//set attachment full path
$attachment_file_path = $base_dir .'/'.$file_dir.'/'.$file_name;
//append new file to mail attachments
$components['attachments'][] = $attachment_file_path;
}
}
}
return $components;
}
I'll leave a full example using wpcf7_before_send_mail to create and store the PDF and wpcf7_mail_components to attach it to the email.
PDF created with FPDF.
<?php
/**
* Plugin Name: Create and attach PDF to CF7 email
* Author: brasofilo
* Plugin URL: https://stackoverflow.com/q/48189010/
*/
!defined('ABSPATH') && exit;
require_once('fpdf/fpdf.php');
add_action('plugins_loaded', array(SendFormAttachment::get_instance(), 'plugin_setup'));
class SendFormAttachment {
protected static $instance = NULL;
public $formID = 5067; # YOUR ID
public $theFile = false;
public function __construct() { }
public static function get_instance() {
NULL === self::$instance and self::$instance = new self;
return self::$instance;
}
public function plugin_setup() {
add_action('wpcf7_before_send_mail', function ( $contact_form, $abort, $submission ) {
if ($contact_form->id() == $this->formID) {
$posted_data = $submission->get_posted_data();
$uploads = wp_upload_dir();
$the_path = $uploads['basedir'] . '/cf7_pdf/';
$fname = $this->createPDF($posted_data, $the_path);
$this->theFile = $the_path . $fname;
}
}, 10, 3);
add_filter( 'wpcf7_mail_components', function( $components ) {
if( $this->theFile )
$components['attachments'][] = $this->theFile;
return $components;
});
}
public function createPDF($posted_data, $savepath) {
$pdf = new FPDF();
$pdf->AliasNbPages();
$pdf->AddPage();
$pdf->SetFont('Times','',12);
$pdf->SetCreator('example.com');
$pdf->SetAuthor('Author name', true);
$pdf->SetTitle('The title', true);
$pdf->SetSubject('The subject', true);
for($i=1;$i<=40;$i++)
$pdf->Cell(0,10,'Printing line number '.$i,0,1);
$filename = rand() . '_' . time() . '.pdf';
$pdf->Output('F', $savepath . $filename);
return $filename;
}
}
The original code would have worked up until V5.4 where add_uploaded_file was made private.
There is a replacement public function you can use to attach the file with the absolute file path:
$submission->add_extra_attachments( $absolute_file_path );
It may also work with paths relative to the wp_uploads folder.
At work, we have a website on which we publish PDF files which are available for download (mostly user notices etc.). We also manage our internal database for updates and to generate CD's and USB Sticks with all PDF files on it, which are shipped out with the products.
So I build a platform where all plants that produce these PDF files can upload them. From time to time, a person will take care of updating the system (sync both servers).
I would like to have a link next to the files with a delete option. I already have that using a simple php script.
<?php
$deleter = new Deleter("./");
class Deleter {
var $filename;
var $ignorelist = array (
'.',
'..',
'index.php',
'del.php',
'deletefile.php'
);
function Deleter($path="./") {
$this->__construct($path);
}
function __construct($path="./") {
$this->filename = basename(__FILE__);
array_push($this->ignorelist, $this->filename);
// insert page header
$this->createHeader();
// condition: create initial file list?
if (isset($_GET['delete']) && !empty($_GET['delete'])) {
// a path has been set, escape and use
$path = basename($_GET['delete']);
$path = urldecode($path);
//$path = mysql_real_escape_string($path);
// condition : Step 2: seek deletion confirmation?
if (!isset($_GET['confirm']) || $_GET['confirm'] != 'aye') {
$this->createConfirmationStep($path);
// step 3: delete!
} else {
$this->createShowDelete($path);
}
// step 1: no files selected, create file list
} else {
echo '
<p>These files are on the server:</p>
<ul>
';
$this->createFileList($path);
echo '</ul>';
}
// insert page footer
$this->createFooter();
}
/**
* Step 1: Create a list of all files within a specific directory
*
* #param string $path The server path to look for files in
* #return array $fileList Array of all files, with file/directory details
* #access public
*/
function createFileList($path) {
// condition : if the path isn't set, assume one
if (!isset($path)) {
$path = "./";
}
// temporary arrays to hold separate file and directory content
$filelist = array();
$directorylist = array();
// get the ignore list, in local scope
$ignorelist = $this->ignorelist;
// Open directory and read contents
if (is_dir($path)) {
// loop through the contents (PHP4 compat)
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
// skip over any files in the ignore list
if (!in_array($file, $ignorelist)) {
// condition : if it is a directory, add to dir list array
if (is_dir($path.$file)) {
$directorylist[] = array(
"path" => $path,
"file" => $file,
"filetype" => 'directory',
"date" => date("M d Y, H:i", filemtime($path.$file."")),
"filecount" => $this->countRelevantFiles($path.$file),
"filesize" => 0
);
// file, add to file array
} else {
$filelist[] = array(
"path" => $path,
"file" => $file,
"filetype" => $this->getFileType($path.$file) . " file",
"date" => date("M d Y, H:i", filemtime($path.$file."")),
"filecount" => 0,
"filesize" => $this->getFileSize(filesize($path.$file))
);
}
}
}
}
// merge file and directory lists
$finalList = array_merge($directorylist, $filelist);
// loop through each file
foreach ($finalList as $key => $value) {
// condition : add trailing slash for directories
$trailingslash = ($value['filetype'] == 'directory' ) ? '/' : '';
// condition : if it is a directory, display count of subfiles
if ($value['filetype'] == 'directory') {
$fileending = ($value['filecount'] == 1) ? 'item' : 'items';
$filedetails = ' (contains '.$value['filecount'].' '.$fileending.')';
// else, if it is a file, display file size
} else {
$filedetails = ' ('.$value['filesize'].')';
}
// create the html for each project
echo '
<li class="' . $value['filetype'].'" id="file_' . urlencode($value['file']) . '">
<strong>' . $value['file'] . '</strong> /
';
echo '
<a href="./'.$this->filename.'?delete='.urlencode($value['file'].$trailingslash).'">
Delete
</a>
</li>
';
}
}
/**
* count the number of files in a directory, not including the list of ignorable files
*
* #param string $path The server path to look for files in
* #return int $count The number of relevant files
* #access private
*/
function countRelevantFiles($path, $count = 0) {
// open the directory
if (is_dir($path)) {
// loop through all files, checking if we should count the current one
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $this->ignorelist)) {
$count++;
if(is_dir($path."/".$file)) {
$count = $this->countRelevantFiles($path."/".$file, $count);
}
}
}
}
// return the result
return $count;
}
/**
* list all sub-files of a directory
*
* #param string $path The server path to look for files in
* #return void
* #access private
*/
function listFilesToDelete($path) {
// open the directory
if (is_dir($path)) {
// loop through all files, checking if we should count the current one
$dh = opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $this->ignorelist)) {
echo '<li>'.$path.'/'.$file.'</li>';
if(is_dir($path."/".$file)) {
$this->listFilesToDelete($path."/".$file);
}
}
}
}
}
/**
* Delete files
*
* #param string $path The server path to delete
* #return void
* #access private
*/
function delete($path) {
// Simple delete for a file
if (is_file($path)) {
echo '<li>deleting file: ' . $path . '</li>';
if (copy($path, "../trash/".$path)) {
unlink($path);
}
}
}
/**
* Create a nice readable filesize from the number of bytes in a file
*
* #param int $size the size in bytes
* #param string $retstring
*
* #return string the size in nice words
*/
function getFileSize($size, $retstring = null)
{
$sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
if ($retstring === null) { $retstring = '%01.2f %s'; }
$lastsizestring = end($sizes);
foreach ($sizes as $sizestring) {
if ($size < 1024) { break; }
if ($sizestring != $lastsizestring) { $size /= 1024; }
}
if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional
return sprintf($retstring, $size, $sizestring);
}
/**
* Function to find a file type for a given filename
*
* #param string $file filename/path
* #return string $extension file type
*/
function getFileType($file="") {
// get file name
$filearray = explode("/", $file);
$filename = array_pop($filearray);
// condition : if no file extension, return
if(strpos($filename, ".") === false) return false;
// get file extension
$filenamearray = explode(".", $filename);
$extension = $filenamearray[(count($filenamearray) - 1)];
return $extension;
}
/* Page Building Methods */
/**
* Create page header
*/
function createHeader(){
echo '
';
}
/**
* Create page footer
*/
function createFooter(){
echo '
';
}
/**
* Create confirmation step
*/
function createConfirmationStep($path){
echo '
<p>� back to file list</p>
<p>Please confirm that you want to delete the following files:</p>
<p class="confirm">Delete</p>
<ol>
<li>'.$path.'</li>
';
$this->listFilesToDelete($path);
echo '
</ol>
<p class="confirm">Delete</p>
';
}
/**
* Show the files you're deleting
*/
function createShowDelete($path){
echo '
<p>� back to file list</p>
<p>The following items have been removed:</p>
<ol>
';
$this->delete($path);
echo '
</ol>
<p><strong>Deletion complete.</strong></p>
<p>� back to file list</p>
';
}
}
?>
Now what I would like this to do is delete a file on one server e.g. server1.com/files/ and move the same file from server2.com/files/ to server2.com/trash/
I have full access to both servers. Is there any way to do that?
since you didn't tell us on what OS you're running you php script, I'm assuming you have a linux.
since you need to do that from one server, you'd need to have a passwordless ssh access to the other server. then you'd need to create a bash script that utilizes mv and rsync to do the file manipulations you need. and then you can use php's exec() function to execute and send the filename param to the shell script from a web page.
I think it's better to configure rsync over ssh with --delete option. Something like this
/usr/bin/rsync -avz --delete /path/files -e "ssh" userforsync#$SECONDARYSERVER:/path/files
where is $SECONDARYSERVER is dns name or ip. To make this work you should accept authentication by public key on secondary server and add public key to authorized keys
i build function to upload zip files but when user upload file two times it didnt delete the first uploaded file but added increment number to the file name (( file.zip,file1.zip,file2.zip,,,etc )
so i want to tell the function when the user uploaded the same file name delete the first file and upload this second file or replace it ... anyone help me how to do that...
/**
* change book source file
*
* #param integer $book_id
*/
public function upload_book_zip($book_id) {
$vars = array();
$vars['upload_path'] = PUBPATH . 'global/modules/bookstore/files/books_source_file/';
$vars['allowed_types'] = 'zip';
$vars['max_size'] = '30720';
$vars['book_id'] = $book_id;
$book = $this->d_book->find_by_id($book_id);
if (isset($_POST['submit'])) {
$file_name = $this->upload($vars);
if ($file_name === NULL) { // error happens while uploading file
$vars['upload_errors'] = $this->upload->display_errors("<p class='notification n-error'>", "</p>");
} else {
$this->d_book->update_one_field($book_id, 'bo_path_zip', $file_name);
$this->session->set_flashdata('success_msg', lang('file_uploaded'));
redirect('bookstore/admin_d_book/');
}
} else {
$vars['upload_errors'] = NULL;
}
if ($book->bo_path_zip) { // load cover image
$vars['file_path'] = base_url() . 'global/modules/bookstore/files/books_source_file/' . $book->bo_path_zip;
} else {
$vars['file_path'] = NULL;
}
$vars['controller_name'] = 'admin_d_book';
$this->view('bookstore/admin/change_zip_file', $vars);
}
/**
*
* #param array $config the configuration array
* #return string
*
*/
private function upload($config) {
$this->load->library('upload', $config);
if (!$this->upload->do_upload("file")) {
return $uploadData['file_name'] = NULL;
} else {
$uploadData = $this->upload->data();
log_message('debug', 'file has been uploaded ok - file name is ' . $uploadData['file_name']);
return $uploadData['file_name'];
}
}
you can do that by adding
$vars['overwrite'] = TRUE;
better check File upload library
Set overwrite to true in the config array you pass
$vars = array();
$vars['upload_path'] = 'filepath here';
$vars['allowed_types'] = 'zip';
$vars['max_size'] = '30720';
$vars['book_id'] = $book_id;
// add this line
$vars['overwrite'] = true;
// the old file will now get overwritten
$file_name = $this->upload($vars)
A better method is to check the md5 or sha1 checksum of the file.
If two users uploads two different files with the same name to the server, the file on server will be overwritten and it is impossible to distingush the file by just name.
Also, it can be done easily in PHP.
By using #usedby tag hyperlink is not coming in documentation.
Class Content
{
/**
* simple db class variable
* #access public
*/
var $_db=null; // db
/**
* s3 class instance
*/
private $_s3=null; // s3
/**
* application variable array for creating instance of each object
* #var array
* #usedby Content::upload() this is compared
*/
public $application=array(
'image'=>array(
'createthumb'=>'createimagethumb'
),
'audio'=>array(
'createthumb'=>'createaudiothumb'
),
'video'=>array(
'createthumb'=>'createvideothumb'
),
'link'=>array(
'createthumb'=>'createlinkthumb'
)
);
/**
* for uploading new content or you can say add new content :)
*
* #return json of new contents
**/
function upload()
{
if ($_POST['gibname']=='' or $_POST['gibview']=='') {
$msg=createmessage(false, 'Please enter gibname and gib view where you want to place content');
}
$maxFileSize = 100 * 1024 * 1024; // Max file size 100 MB
$thumb = $status =$imgWidth = $imgHeight = '';
$headers = apache_request_headers(); // Get file size from Apache headers
$fileSize=(int)$headers['Content-Length'];
$fileType = (string)$headers['Content-Type']; // Get MIME type from Apache headers
$clientfileType = $fileType;
if (preg_match("/^multipart/", $fileType) ) $fileType = $_FILES['qqfile']['type'];
if ($fileType=='application/octet-stream') $fileType="video/flv";
if ($fileSize == 0) {
return array('success'=>false, 'error'=>"File is empty.");
}
if ($fileSize > $maxFileSize) {
return array('success'=>false, 'error'=>"File is too large.");
}
$pathinfo = pathinfo($_REQUEST['qqfile']); // Put data of pathinfo() array into $pathinfo
$filename = $pathinfo['filename'];// Get file name - eg: myphoto
$ext = $pathinfo['extension']; // Get extension - eg: .jpg
if ($ext=='') $ext=substr(strrchr($_FILES['qqfile']['name'], '.'), 1);
$originalName = $filename.'.'.$ext;
$randName = uniqid(); // Generate unique id for the current object
$fileTempName = $randName . '.' . $ext; // Unique file name with extension
$fullTempName = "uploads/".$fileTempName; // Set temp directory where files will be written temporarily // Complete temp file name and path
if (!preg_match("/^multipart/", $clientfileType)) { // Upload the file to temp directory on .net server
$input = fopen("php://input", "r");
$fp = fopen($fullTempName, "w");
while ($data = fread($input, 1024)) {
fwrite($fp,$data);
}
fclose($fp);
fclose($input);
} else
move_uploaded_file($_FILES["qqfile"]["tmp_name"], $fullTempName);
$objecttype=mb_substr($fileType,0,-mb_strlen(strrchr($fileType,"/")));
//for uploading of link url is neccesssary
if ($_POST['url']!='' or $_POST['refername']!='') {
$objecttype="link";
$url=$_POST['url'];
$filename=$_POST['filename'];
} else {
$url=CLOUDFRONT.$fileTempName;
$filename=$fileTempName;
}
if (class_exists($objecttype) && $_POST['refername']=='') {
$object=new $objecttype();
$str=$this->application[$objecttype]['createthumb'];
$thumb=$object->{$str}($fullTempName,$fileType);
$thumbnail=$thumb['thumb'];
$preview=$thumb['preview'];
$imgWidth=$object->imagewidth;
$imgHeight=$object->imageheight;
$resize=$object->resize;
}
}
While #usedby is not the warning is coming telling unknown tag .
phpdocumentor version is 1.4.3
why it is saying the unknown tag .
The "#usedby" tag is not a code documentation tag that phpDocumentor looks for in your docblocks. There is a "#uses" tag that says "this particular element uses the one I'm listing in this tag". phpDocumentor will see this tag, show this tag on the element's doc, make a link to the other element, and put a #usedby tag in the documentation for that other element.
In short, you put #uses in ThisElement's docblock to point from ThisElement to ThatElement, and phpDocumentor will put #usedby in ThatElement's documentation to point from ThatElement back to ThisElement.
I have a Drupal site that needs to display a unique header image based on the path. I have found some helpful code. It gets me close to where I need to be, but not all the way. I have pasted it at the end of this post.
The issue I am having is that it bases the banner image off of the characters after the first "/" after example.com in the URL. For example, example.com/forum returns a banner of header-FORUM.png.
I need it to work a little differently. I would like it to base the banner returned off the characters after the second "/" after example.com in the URL. For example, example.com/category/term should return a banner of header-TERM.png.
Any help that you can offer with this is much appreciated.
Here's the code I mentioned earlier via AdaptiveThemes (FYI, there is a comment on that page that attempts to solve a similar issue to mine but I can't get it to work).
<?php
// Return a file based on the URL alias, else return a default file
function unique_section_header() {
$path = drupal_get_path_alias($_GET['q']);
list($sections, ) = explode('/', $path, 2);
$section = safe_string($sections);
$filepath = path_to_theme() . '/images/sections/header-' . $section .'.png';
if (file_exists($filepath)) {
$output = $filepath;
}
else {
$output = path_to_theme() . '/images/sections/header-default.png';
}
return $output;
}
//Make a string safe
function safe_string($string) {
$string = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
return $string;
}
?>
Thanks!
Not exactly sure what the output of drupal_get_path_alias is, but try this:
<?php
// Return a file based on the URL alias, else return a default file
function unique_section_header() {
$path = drupal_get_path_alias($_GET['q']);
$pathSegments = explode('/', $path, 3);
$section = safe_string($pathSegments[2]);
$filepath = path_to_theme() . '/images/sections/header-' . $section .'.png';
if (file_exists($filepath)) {
$output = $filepath;
}
else {
$output = path_to_theme() . '/images/sections/header-default.png';
}
return $filepath;//$output;
}
//Make a string safe
function safe_string($string) {
$string = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
return $string;
}
The only changes made were to the usage of explode. explode will separate the path based on the /, so you just need to access a different element in that array. The last parameter of explode is the maximum number of elements to be returned and may also need to be tweaked
I'm adding an answer so I can include code. This is based on Gilean's response.
/** Return a file based on the URL alias, else return a default file
*/
function unique_section_header() {
$path = drupal_get_path_alias($_GET['q']);
$pathSegments = explode('/', $path, 3);
$section = safe_string($pathSegments[1]);
$filepath = path_to_theme() . '/images/sections/header-' . $section .'.png';
if (file_exists($filepath)) {
$output = $filepath;
}
else {
$output = path_to_theme() . '/images/sections/header-default.jpg';
}
return $output;
}
/** Make a string safe
*/
function safe_string($string) {
$string = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
return $string;
}
This is what I would do:
In your theme's template.php, create the function THEMENAME_preprocess_page (replace THEMENAME with the name of your theme) as follows. If it already exists, add the following code to that function. (disclamer: untested code)
function THEMENAME_preprocess_page(&$variables) {
$path = drupal_get_path_alias($_GET['q']);
$path_segments = explode('/', $path, 3);
if ($path_segments[0] == 'category' && !empty($path_segments[1])) {
$safe_term = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $path_segments[1]));
$filepath = path_to_theme() . '/images/sections/header-' . $safe_term .'.png';
if (!file_exists($filepath)) {
$filepath = path_to_theme() . '/images/sections/header-default.png';
}
$variables['header_image'] = theme('image', $filepath);
}
}
Using a preprocess function (like the one above) is the Drupal way to make extra variables available for a template file. You only have to add a new element to the $variables array. Once you have done the above, you can simply put the following line in your page.tpl.php:
<?php print $header_image; ?>
This will print the complete <img> element.
PS. Usually, I advice not to base code like this on path aliases. It's a method that breaks easily because path aliases can change.