Related
Based on: http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html
I made an Images Model:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Filesystem\Filesystem;
/**
* #ORM\Entity
* #ORM\Table(name="images")
* #ORM\Entity(repositoryClass="AppBundle\Entity\ImagesRepository")
* #ORM\HasLifecycleCallbacks
*/
class Images
{
/**
* #ORM\Column(type="string", length=60)
* #ORM\Id
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class="AppBundle\Doctrine\AutoIdGenerate")
*/
private $id;
/**
* Filename of the Image
* #ORM\Column(type="string", length=100)
*/
private $name;
/**
* Filename of the Thumbnail
* #ORM\Column(type="string", length=100)
*/
private $name_small;
/**
* ImageGroup og the Image
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\ImageGroups", inversedBy="images")
*/
private $group;
/**
* #Assert\File(maxSize="20000000")
*/
private $file;
private $upload_dir='images';
private $temp;
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file,$upload_dir)
{
$this->file = $file;
// check if we have an old image path
if (isset($this->name))
{
// store the old name to delete after the update
$this->temp = $this->name;
$this->name = null;
}
else
{
$this->name = sha1(uniqid(mt_rand(), true)).'.'.$file->guessExtension();
}
$this->name_small="small_".$this->name;
$this->upload_dir=$upload_dir;
return $this;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile())
{
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->name = $filename.'.'.$this->getFile()->guessExtension();
$this->name_small='small_'.$this->name;
}
}
public function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->upload_dir;
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile())
{
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
//-- Make the Thumbnail Here --
$dir=$this->getUploadRootDir();
echo $dir;
$fs = new Filesystem();
if(!$fs->exists($dir))
{
echo "\nCreating\n";
$fs->mkdir($dir,0777,true);
}
$this->getFile()->move($dir, $this->name);
$file=$dir.'/'.$this->name;
// check if we have an old image
if (isset($this->temp))
{
// delete the old image
unlink($this->getUploadRootDir().'/'.$this->temp);
// clear the temp image path
$this->temp = null;
}
$this->file = null;
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
$file = $this->getAbsolutePath();
if ($file)
{
unlink($file);
}
}
/**
* Get id
*
* #return string
*/
public function getId()
{
return $this->id;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Get nameSmall
*
* #return string
*/
public function getNameSmall()
{
return $this->name_small;
}
/**
* Set group
*
* #param \AppBundle\Entity\ImageGroups $group
*
* #return Images
*/
public function setGroup(\AppBundle\Entity\ImageGroups $group = null)
{
$this->group = $group;
return $this;
}
/**
* Get group
*
* #return \AppBundle\Entity\ImageGroups
*/
public function getGroup()
{
return $this->group;
}
/**
* Set name
*
* #param string $name
*
* #return Images
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Set nameSmall
*
* #param string $nameSmall
*
* #return Images
*/
public function setNameSmall($nameSmall)
{
$this->name_small = $nameSmall;
return $this;
}
}
I also made a Custom Repository In order to do the Uploads:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use AppBundle\Entity\Images;
class ImagesRepository extends EntityRepository
{
public function add($file,$group_id,$user_id)
{
if(empty($group_id)) return -1;
if(empty($user_id)) return -2;
/*Do stuff for uploads*/
/*End of Do stuff for uploads*/
$em = $this->getEntityManager();
$imagesGroups = $em->getRepository('AppBundle:ImageGroups')
->getUserImageGroups($user_id,null,$group_id);
if(empty($imagesGroups) ||(is_int($imagesGroups) && $imagesGroups<0)) return -3; //Null and negative values are false
if(empty($file)) return -4;
$image=new Images();
$image->setFile($file,'images')->setGroup($imagesGroups);
try
{
$em->persist($image);
$em->flush();
return ['id'=>$image->getId(),'image'=>$image->getName(),'thumb'=>$image->getNameSmall()];
}
catch (\Exception $e)
{
echo $e->getMessage();
return false;
}
}
public function delete($user_id,$image_id)
{
if(empty($image_id)) return -1;
if(empty($user_id)) return -2;
$em = $this->getEntityManager();
try
{
$q=$em->createQueryBuilder('i')
->from('AppBundle:Images','i')
->innerJoin('i.group', 'g')
->innerJoin('AppBundle:Users','u')
->select('i')
->where('i.id=:iid')
->andWhere('u.id=:uid')
->setParameter(':uid', $user_id)
->setParameter(':iid', $image_id)
->setMaxResults(1)
->getQuery();
$data=$q->getOneOrNullResult();
if(empty($data)) return -3;
/*Delete Image Stuff*/
/*End Of: Delete Image Stuff*/
$em->remove($data);
$em->flush();
return true;
}
catch (\Exception $e)
{
echo $e->getMessage();
return false;
}
}
}
When I sucessfully do the POST action (I Use curl to test the code above) for some reason I get the following Error:
The file "IMG_20160305_155302.jpg" was not uploaded due to an unknown error.
By echoing the Exception message.
I Originally thought that is a permissions Issues on my filesystem therefore on the Folder /home/pcmagas/Kwdikas/php/apps/symphotest/src/AppBundle/Entity/../../../../web/images
I set the following permissions:
drwxrwxrwx 2 www-data www-data 4096 Μάρ 5 23:02 images
But it does not seem that is the problem. And I wonder what else could it be.
May I have a solution?
Edit 1:
I checked the upload_max_filesize on php.ini and is on 2M and the file that I am Uploading is on 56,0 Kbytes.
The UploadedFile Instance somehow was not setup corectly in controller.
In order to get the file Input I made this class:
<?php
namespace AppBundle\Helpers;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class MyUploadedFile
{
/**
*Storing Uploaded Files
*/
private $files=null;
function __construct($string)
{
if(isset($_FILES[$string]))
{
$files=$_FILES[$string];
if(is_array($files['name']))
{
$this->files=array();
$tmp_files=array();
/**
*Sanitizing When Multiple Files
*/
foreach($files as $key=>$val)
{
foreach($val as $key2=>$val2)
{
$tmp_files[$key2][$key]=$val2;
}
}
foreach($tmp_files as $val)
{
$this->files[]=new UploadedFile($val['tmp_name'],$val['name'],$val['type'],$val['size'],$val['error']);
}
}
elseif(is_string($files['name']))
{
$this->files= new UploadedFile($files['tmp_name'],$files['name'],$files['type'],$files['size'],$files['error']);
}
}
}
/**
*#return {UploadedFile} Or {Array of UploadedFile} or null
*/
public function getFiles()
{
return $this->files;
}
}
?>
Especially in these lines
$this->files= new UploadedFile($files['tmp_name'],$files['name'],$files['type'],$files['size'],$files['error']);
$this->files[]=new UploadedFile($val['tmp_name'],$val['name'],$val['type'],$val['size'],$val['error']);
So when ytou manually make an uploaded file the size comes before the error
I'm trying to create two custom providers, one for PDF and another one for ZIP files.
This is my code.
services.yml
parameters:
application_sonata_media.zip_class: Application\Sonata\MediaBundle\Provider\ZipProvider
services:
sonata.media.provider.zip:
class: %application_sonata_media.zip_class%
tags:
- { name: sonata.media.provider }
arguments:
- sonata.media.provider.zip
- #sonata.media.filesystem.local
- #sonata.media.cdn.server
- #sonata.media.generator.default
- #sonata.media.thumbnail.format
- ['zip']
- ['application/zip']
sonata_media.yml
sonata_media:
contexts:
eag_zip:
download:
strategy: sonata.media.security.public_strategy
mode: http
providers:
- sonata.media.provider.zip
formats:
reference: { quality: 100 }
ZipProvider.php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace Application\Sonata\MediaBundle\Provider;
use Sonata\MediaBundle\Provider\BaseProvider;
use Gaufrette\Filesystem;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\CoreBundle\Model\Metadata;
use Sonata\MediaBundle\CDN\CDNInterface;
use Sonata\MediaBundle\Generator\GeneratorInterface;
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface;
use Sonata\MediaBundle\Model\MediaInterface;
use Sonata\MediaBundle\Thumbnail\ThumbnailInterface;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
/**
* Description of ZipProvider
*
* #author Juanjo García <juanjogarcia#editartgroup.com>
*/
class ZipProvider extends BaseProvider {
protected $allowedExtensions;
protected $allowedMimeTypes;
protected $metadata;
/**
* #param string $name
* #param \Gaufrette\Filesystem $filesystem
* #param \Sonata\MediaBundle\CDN\CDNInterface $cdn
* #param \Sonata\MediaBundle\Generator\GeneratorInterface $pathGenerator
* #param \Sonata\MediaBundle\Thumbnail\ThumbnailInterface $thumbnail
* #param array $allowedExtensions
* #param array $allowedMimeTypes
* #param \Sonata\MediaBundle\Metadata\MetadataBuilderInterface $metadata
*/
public function __construct($name, Filesystem $filesystem, CDNInterface $cdn, GeneratorInterface $pathGenerator, ThumbnailInterface $thumbnail, array $allowedExtensions = array(), array $allowedMimeTypes = array(), MetadataBuilderInterface $metadata = null)
{
parent::__construct($name, $filesystem, $cdn, $pathGenerator, $thumbnail);
$this->allowedExtensions = $allowedExtensions;
$this->allowedMimeTypes = $allowedMimeTypes;
$this->metadata = $metadata;
}
/**
* {#inheritdoc}
*/
public function getProviderMetadata()
{
return new Metadata($this->getName(), $this->getName().'.description', false, 'SonataMediaBundle', array('class' => 'fa fa-file-text-o'));
}
/**
* {#inheritdoc}
*/
public function getReferenceImage(MediaInterface $media)
{
return sprintf('%s/%s',
$this->generatePath($media),
$media->getProviderReference()
);
}
/**
* {#inheritdoc}
*/
public function getReferenceFile(MediaInterface $media)
{
return $this->getFilesystem()->get($this->getReferenceImage($media), true);
}
/**
* {#inheritdoc}
*/
public function buildEditForm(FormMapper $formMapper)
{
$formMapper->add('name');
$formMapper->add('enabled', null, array('required' => false));
$formMapper->add('authorName');
$formMapper->add('cdnIsFlushable');
$formMapper->add('description');
$formMapper->add('copyright');
$formMapper->add('binaryContent', 'file', array('required' => false));
}
/**
* {#inheritdoc}
*/
public function buildCreateForm(FormMapper $formMapper)
{
$formMapper->add('binaryContent', 'file', array(
'constraints' => array(
new NotBlank(),
new NotNull(),
),
));
}
/**
* {#inheritdoc}
*/
public function buildMediaType(FormBuilder $formBuilder)
{
$formBuilder->add('binaryContent', 'file');
}
/**
* {#inheritdoc}
*/
public function postPersist(MediaInterface $media)
{
if ($media->getBinaryContent() === null) {
return;
}
$this->setFileContents($media);
$this->generateThumbnails($media);
}
/**
* {#inheritdoc}
*/
public function postUpdate(MediaInterface $media)
{
if (!$media->getBinaryContent() instanceof \SplFileInfo) {
return;
}
// Delete the current file from the FS
$oldMedia = clone $media;
$oldMedia->setProviderReference($media->getPreviousProviderReference());
$path = $this->getReferenceImage($oldMedia);
if ($this->getFilesystem()->has($path)) {
$this->getFilesystem()->delete($path);
}
$this->fixBinaryContent($media);
$this->setFileContents($media);
$this->generateThumbnails($media);
}
/**
* #throws \RuntimeException
*
* #param \Sonata\MediaBundle\Model\MediaInterface $media
*
* #return
*/
protected function fixBinaryContent(MediaInterface $media)
{
if ($media->getBinaryContent() === null) {
return;
}
// if the binary content is a filename => convert to a valid File
if (!$media->getBinaryContent() instanceof File) {
if (!is_file($media->getBinaryContent())) {
throw new \RuntimeException('The file does not exist : '.$media->getBinaryContent());
}
$binaryContent = new File($media->getBinaryContent());
$media->setBinaryContent($binaryContent);
}
}
/**
* #throws \RuntimeException
*
* #param \Sonata\MediaBundle\Model\MediaInterface $media
*/
protected function fixFilename(MediaInterface $media)
{
if ($media->getBinaryContent() instanceof UploadedFile) {
$media->setName($media->getName() ?: $media->getBinaryContent()->getClientOriginalName());
$media->setMetadataValue('filename', $media->getBinaryContent()->getClientOriginalName());
} elseif ($media->getBinaryContent() instanceof File) {
$media->setName($media->getName() ?: $media->getBinaryContent()->getBasename());
$media->setMetadataValue('filename', $media->getBinaryContent()->getBasename());
}
// this is the original name
if (!$media->getName()) {
throw new \RuntimeException('Please define a valid media\'s name');
}
}
/**
* {#inheritdoc}
*/
protected function doTransform(MediaInterface $media)
{
$this->fixBinaryContent($media);
$this->fixFilename($media);
// this is the name used to store the file
if (!$media->getProviderReference()) {
$media->setProviderReference($this->generateReferenceName($media));
}
if ($media->getBinaryContent()) {
$media->setContentType($media->getBinaryContent()->getMimeType());
$media->setSize($media->getBinaryContent()->getSize());
}
$media->setProviderStatus(MediaInterface::STATUS_OK);
}
/**
* {#inheritdoc}
*/
public function updateMetadata(MediaInterface $media, $force = true)
{
// this is now optimized at all!!!
$path = tempnam(sys_get_temp_dir(), 'sonata_update_metadata');
$fileObject = new \SplFileObject($path, 'w');
$fileObject->fwrite($this->getReferenceFile($media)->getContent());
$media->setSize($fileObject->getSize());
}
/**
* {#inheritdoc}
*/
public function generatePublicUrl(MediaInterface $media, $format)
{
if ($format == 'reference') {
$path = $this->getReferenceImage($media);
} else {
// #todo: fix the asset path
$path = sprintf('sonatamedia/files/%s/file.png', $format);
}
return $this->getCdn()->getPath($path, $media->getCdnIsFlushable());
}
/**
* {#inheritdoc}
*/
public function getHelperProperties(MediaInterface $media, $format, $options = array())
{
return array_merge(array(
'title' => $media->getName(),
'thumbnail' => $this->getReferenceImage($media),
'file' => $this->getReferenceImage($media),
), $options);
}
/**
* {#inheritdoc}
*/
public function generatePrivateUrl(MediaInterface $media, $format)
{
if ($format == 'reference') {
return $this->getReferenceImage($media);
}
return false;
}
/**
* Set the file contents for an image.
*
* #param \Sonata\MediaBundle\Model\MediaInterface $media
* #param string $contents path to contents, defaults to MediaInterface BinaryContent
*/
protected function setFileContents(MediaInterface $media, $contents = null)
{
$file = $this->getFilesystem()->get(sprintf('%s/%s', $this->generatePath($media), $media->getProviderReference()), true);
if (!$contents) {
$contents = $media->getBinaryContent()->getRealPath();
}
$metadata = $this->metadata ? $this->metadata->get($media, $file->getName()) : array();
$file->setContent(file_get_contents($contents), $metadata);
}
/**
* #param \Sonata\MediaBundle\Model\MediaInterface $media
*
* #return string
*/
protected function generateReferenceName(MediaInterface $media)
{
return sha1($media->getName().rand(11111, 99999)).'.'.$media->getBinaryContent()->guessExtension();
}
/**
* {#inheritdoc}
*/
public function getDownloadResponse(MediaInterface $media, $format, $mode, array $headers = array())
{
// build the default headers
$headers = array_merge(array(
'Content-Type' => $media->getContentType(),
'Content-Disposition' => sprintf('attachment; filename="%s"', $media->getMetadataValue('filename')),
), $headers);
if (!in_array($mode, array('http', 'X-Sendfile', 'X-Accel-Redirect'))) {
throw new \RuntimeException('Invalid mode provided');
}
if ($mode == 'http') {
if ($format == 'reference') {
$file = $this->getReferenceFile($media);
} else {
$file = $this->getFilesystem()->get($this->generatePrivateUrl($media, $format));
}
return new StreamedResponse(function () use ($file) {
echo $file->getContent();
}, 200, $headers);
}
if (!$this->getFilesystem()->getAdapter() instanceof \Sonata\MediaBundle\Filesystem\Local) {
throw new \RuntimeException('Cannot use X-Sendfile or X-Accel-Redirect with non \Sonata\MediaBundle\Filesystem\Local');
}
$filename = sprintf('%s/%s',
$this->getFilesystem()->getAdapter()->getDirectory(),
$this->generatePrivateUrl($media, $format)
);
return new BinaryFileResponse($filename, 200, $headers);
}
/**
* {#inheritdoc}
*/
public function validate(ErrorElement $errorElement, MediaInterface $media)
{
if (!$media->getBinaryContent() instanceof \SplFileInfo) {
return;
}
if ($media->getBinaryContent() instanceof UploadedFile) {
$fileName = $media->getBinaryContent()->getClientOriginalName();
} elseif ($media->getBinaryContent() instanceof File) {
$fileName = $media->getBinaryContent()->getFilename();
} else {
throw new \RuntimeException(sprintf('Invalid binary content type: %s', get_class($media->getBinaryContent())));
}
if (!in_array(strtolower(pathinfo($fileName, PATHINFO_EXTENSION)), $this->allowedExtensions)) {
$errorElement
->with('binaryContent')
->addViolation('Invalid extensions')
->end();
}
if (!in_array($media->getBinaryContent()->getMimeType(), $this->allowedMimeTypes)) {
$errorElement
->with('binaryContent')
->addViolation('Invalid mime type : '.$media->getBinaryContent()->getMimeType())
->end();
}
}
}
When I push create and edit button, the file pass the validation, save in DDBB and file in server, but in URL /admin/sonata/media/media/233/edit?provider=sonata.media.provider.zip&context=eag_zip I get this Error message:
Unable to find template "" in SonataMediaBundle:MediaAdmin:edit.html.twig at line 48.
Trying to go to /admin/sonata/media/media/list?provider=sonata.media.provider.zip&context=eag_zip or /admin/sonata/media/media/list?context=eag_zip
Unable to find template "" in SonataMediaBundle:MediaAdmin:inner_row_media.html.twig at line 19.
I don't know to solve it.
any help would be welcome
thanks a lot
Solved here
services:
sonata.media.provider.zip:
class: %application_sonata_media.zip_class%
tags:
- { name: sonata.media.provider }
arguments:
- sonata.media.provider.zip
- #sonata.media.filesystem.local
- #sonata.media.cdn.server
- #sonata.media.generator.default
- #sonata.media.thumbnail.format
- ['zip']
- ['application/zip']
calls:
- [ setTemplates, [{helper_view:SonataMediaBundle:Provider:view_image.html.twig,helper_thumbnail:SonataMediaBundle:Provider:thumbnail.html.twig}]]
I am trying to find a way to transfer files from server-to-server. The source server can be any platform, and we may not even really know anything about it except that it supports FTP.
A number of posts I have found on SO recommend using scp, sftp, rsync, or wget for this purpose. Given that this PHP script needs to work every time, and the only thing we know for sure is that the source server supports FTP, how can this be achieved?
I found a couple FTP examples on SO, but they weren't explained very well.
We need to be able to download all files and folders, keeping the same directory structure as well.
I have found a PHP class that makes recursive FTP uploads and downloads easy. It can be found here
The code they used is below (The code at the top is example code for downloads, uploads, and error checking):
<?php // example
set_time_limit(0);
require 'ftp.php';
$ftp = new ftp();
$ftp->conn('host', 'username', 'password');
$ftp->get('download/demo', '/demo'); // download live "/demo" folder to local "download/demo"
$ftp->put('/demo/test', 'upload/vjtest'); // upload local "upload/vjtest" to live "/demo/test"
$arr = $ftp->getLogData();
if ($arr['error'] != "")
echo '<h2>Error:</h2>' . implode('<br />', $arr['error']);
if ($arr['ok'] != "")
echo '<h2>Success:</h2>' . implode('<br />', $arr['ok']);
class ftp {
private $conn, $login_result, $logData, $ftpUser, $ftpPass, $ftpHost, $retry, $ftpPasv, $ftpMode, $verbose, $logPath, $createMask;
// --------------------------------------------------------------------
/**
* Construct method
*
* #param array keys[passive_mode(true|false)|transfer_mode(FTP_ASCII|FTP_BINARY)|reattempts(int)|log_path|verbose(true|false)|create_mask(default:0777)]
* #return void
*/
function __construct()
{
$this->retry = (isset($o['reattempts'])) ? $o['reattempts'] : 3;
$this->ftpPasv = (isset($o['passive_mode'])) ? $o['passive_mode'] : true;
$this->ftpMode = (isset($o['transfer_mode'])) ? $o['transfer_mode'] : FTP_BINARY;
$this->verbose = (isset($o['verbose'])) ? $o['verbose'] : false;
$this->logPath = (isset($o['log_path'])) ? $o['log_path'] : dirname(__FILE__).'\log';
$this->createMask = (isset($o['create_mask'])) ? $o['create_mask'] : 0777;
}
// --------------------------------------------------------------------
/**
* Connection method
*
* #param string hostname
* #param string username
* #param string password
* #return void
*/
public function conn($hostname, $username, $password)
{
$this->ftpUser = $username;
$this->ftpPass = $password;
$this->ftpHost = $hostname;
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Init connection method - connect to ftp server and set passive mode
*
* #return bool
*/
function initConn()
{
$this->conn = ftp_connect($this->ftpHost);
$this->login_result = ftp_login($this->conn, $this->ftpUser, $this->ftpPass);
if($this->conn && $this->login_result)
{
ftp_pasv($this->conn, $this->ftpPasv);
return true;
}
return false;
}
// --------------------------------------------------------------------
/**
* Put method - upload files(folders) to ftp server
*
* #param string path to destionation file/folder on ftp
* #param string path to source file/folder on local disk
* #param int only for identify reattempt, dont use this param
* #return bool
*/
public function put($destinationFile, $sourceFile, $retry = 0)
{
if(file_exists($sourceFile))
{
if(!$this->isDir($sourceFile, true))
{
$this->createSubDirs($destinationFile);
if(!ftp_put($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when uploading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."\n";
$this->reconnect();
$this->put($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Upload:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'put');
}
}
}
// --------------------------------------------------------------------
/**
* Get method - download files(folders) from ftp server
*
* #param string path to destionation file/folder on local disk
* #param string path to source file/folder on ftp server
* #param int only for identify reattempt, dont use this param
* #return bool
*/
public function get($destinationFile, $sourceFile, $retry = 0)
{
if(!$this->isDir($sourceFile, false))
{
if($this->verbose)echo $sourceFile.' => '.$destinationFile."\n";
$this->createSubDirs($destinationFile, false, true);
if(!ftp_get($this->conn, $destinationFile, $sourceFile, $this->ftpMode))
{
$retry++;
if($retry > $this->retry)
{
$this->logData('Error when downloading file: '.$sourceFile.' => '.$destinationFile, 'error');
return false;
}
if($this->verbose) echo 'Retry: '.$retry."\n";
$this->reconnect();
$this->get($destinationFile, $sourceFile, $retry);
}
else
{
$this->logData('Download:'.$sourceFile.' => '.$destinationFile, 'ok');
return true;
}
}
else
{
$this->recursive($destinationFile, $sourceFile, 'get');
}
}
// --------------------------------------------------------------------
/**
* Make dir method - make folder on ftp server or local disk
*
* #param string path to destionation folder on ftp or local disk
* #param bool true for local, false for ftp
* #return bool
*/
public function makeDir($dir, $local = false)
{
if($local)
{
if(!file_exists($dir) && !is_dir($dir))return mkdir($dir, $this->createMask); else return true;
}
else
{
ftp_mkdir($this->conn,$dir);
return ftp_chmod($this->conn, $this->createMask, $dir);
}
}
// --------------------------------------------------------------------
/**
* Cd up method - change working dir up
*
* #param bool true for local, false for ftp
* #return bool
*/
public function cdUp($local)
{
return $local ? chdir('..') : ftp_cdup($this->conn);
}
// --------------------------------------------------------------------
/**
* List contents of dir method - list all files in specified directory
*
* #param string path to destionation folder on ftp or local disk
* #param bool true for local, false for ftp
* #return bool
*/
public function listFiles($file, $local = false)
{
if(!$this->isDir($file, $local))return false;
if($local)
{
return scandir($file);
}
else
{
if(!preg_match('/\//', $file))
{
return ftp_nlist($this->conn, $file);
}else
{
$dirs = explode('/', $file);
foreach($dirs as $dir)
{
$this->changeDir($dir, $local);
}
$last = count($dirs)-1;
$this->cdUp($local);
$list = ftp_nlist($this->conn, $dirs[$last]);
$i = 0;
foreach($dirs as $dir)
{
if($i < $last) $this->cdUp($local);
$i++;
}
return $list;
}
}
}
// --------------------------------------------------------------------
/**
* Returns current working directory
*
* #param bool true for local, false for ftp
* #return bool
*/
public function pwd($local = false)
{
return $local ? getcwd() : ftp_pwd($this->conn);
}
// --------------------------------------------------------------------
/**
* Change current working directory
*
* #param string dir name
* #param bool true for local, false for ftp
* #return bool
*/
public function changeDir($dir, $local = false)
{
return $local ? chdir($dir) : #ftp_chdir($this->conn, $dir);
}
// --------------------------------------------------------------------
/**
* Create subdirectories
*
* #param string path
* #param bool
* #param bool true for local, false for ftp
* #param bool change current working directory back
* #return void
*/
function createSubDirs($file, $last = false, $local = false, $chDirBack = true)
{
if(preg_match('/\//',$file))
{
$origin = $this->pwd($local);
if(!$last) $file = substr($file, 0, strrpos($file,'/'));
$dirs = explode('/',$file);
foreach($dirs as $dir)
{
if(!$this->isDir($dir, $local))
{
$this->makeDir($dir, $local);
$this->changeDir($dir, $local);
}
else
{
$this->changeDir($dir, $local);
}
}
if($chDirBack) $this->changeDir($origin, $local);
}
}
// --------------------------------------------------------------------
/**
* Recursion
*
* #param string destionation file/folder
* #param string source file/folder
* #param string put or get
* #return void
*/
function recursive($destinationFile, $sourceFile, $mode)
{
$local = ($mode == 'put') ? true : false;
$list = $this->listFiles($sourceFile, $local);
if($this->verbose) echo "\n".'Folder: '.$sourceFile."\n";
$this->logData(($mode=='get')?('Download:'):('Upload:').$sourceFile.' => '.$destinationFile, 'ok');
if($this->verbose) print_r($list);
$x=0;
$z=0;
if(count($list)==2)// blank folder
{
if($mode == 'get')
$this->makeDir($destinationFile, true);
if($mode == 'put')
$this->makeDir($destinationFile);
}
foreach($list as $file)
{
if($file == '.' || $file == '..')continue;
$destFile = $destinationFile.'/'.$file;
$srcFile = $sourceFile.'/'.$file;
if($this->isDir($srcFile,$local))
{
$this->recursive($destFile, $srcFile, $mode);
}
else
{
if($local)
{
$this->put($destFile, $srcFile);
}
else
{
$this->get($destFile, $srcFile);
}
}
}
}
// --------------------------------------------------------------------
/**
* Check if is dir
*
* #param string path to folder
* #return bool
*/
public function isDir($dir, $local)
{
if($local) return is_dir($dir);
if($this->changeDir($dir))return $this->cdUp(0);
return false;
}
// --------------------------------------------------------------------
/**
* Save log data to array
*
* #param string data
* #param string type(error|ok)
* #return void
*/
function logData($data, $type)
{
$this->logData[$type][] = $data;
}
// --------------------------------------------------------------------
/**
* Get log data array
*
* #return array
*/
public function getLogData()
{
return $this->logData;
}
// --------------------------------------------------------------------
/**
* Save log data to file
*
* #return void
*/
public function logDataToFiles()
{
if(!$this->logPath) return false;
$this->makeDir($this->logPath, true);
$log = $this->getLogData();
$sep = "\n".date('y-m-d H:i:s').' ';
if($log['error'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['error'])."\n";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-error.log',$logc);
}
if($log['ok'] != "")
{
$logc = date('y-m-d H:i:s').' '.join($sep,$log['ok'])."\n";
$this->addToFile($this->logPath.'/'.$this->ftpUser.'-ok.log',$logc);
}
}
// --------------------------------------------------------------------
/**
* Reconnect method
*
* #return void
*/
public function reconnect()
{
$this->closeConn();
$this->initConn();
}
// --------------------------------------------------------------------
/**
* Close connection method
*
* #return void
*/
public function closeConn()
{
return ftp_close($this->conn);
}
// --------------------------------------------------------------------
/**
* Write to file
*
* #param string path to file
* #param string text
* #param string fopen mode
* #return void
*/
function addToFile($file, $ins, $mode = 'a')
{
$fp = fopen($file, $mode);
fwrite($fp,$ins);
fclose($fp);
}
// --------------------------------------------------------------------
/**
* Destruct method - close connection and save log data to file
*
* #return void
*/
function __destruct()
{
$this->closeConn();
$this->logDataToFiles();
}
}
// END ftp class
/* End of file ftp.php */
/* Location: ftp.php */
This should be a comment, but its a bit long. Copying a file over FTP using PHP might be as simple as
file_put_contents($fname
, file_get_contents('FTP://ftp.example com/path/afile'));
But what do you know about where your PHP code is running? It may not have the capability to
resolve DNS names
make client connections to other/remote services
create a listening data channel (for non-passive data channel)
And we can't answer these questions for you. Hence your first step is to get a proof of concept up and running using similar code to that above before you start worrying about lots of files, directories and synchronisation.
Why the requirement to implement this in PHP?
I am trying to write a class that will allow me to write data to a file and then read it. In some cases, I also lock the file for write, then unlock it once the writing is done.
The problem that I am having is when trying to get the content of the file using my getCache() method the file becomes empty. It seems that when the getCache() method is called the content of the file are deleted for some reason.
Here is my class
<?php
namespace ICWS;
use \ICWS\showVar;
use \DirectoryIterator;
/**
* CacheHandler
*
* #package ICWS
*/
class CacheHandler {
/* Max time second allowed to keep a session File */
private $maxTimeAllowed = 300;
private $filename = '';
private $handle;
public function __construct( $filename ){
$this->filename = $filename;
// 5% chance to collect garbage when the class is initialized.
if(rand(1, 100) <= 5){
$this->collectGarbage();
}
}
/**
* Add/Update the cached array in the session
*
* #param string $key
* #param bigint $id
* #param array $field
* #return void
*/
public function updateCache($key, $id, array $field)
{
$currentVal = (object) $field;
$this->openFile();
$this->lockFile();
$storage = $this->readFile();
//create a new if the $id does not exists in the cache
if( isset($storage[$key]) && array_key_exists($id, $storage[$key]) ){
$currentVal = (object) $storage[$key][$id];
foreach($field as $k => $v){
$currentVal->$k = $v; //update existing key or add a new one
}
}
$storage[$key][$id] = $currentVal;
new showVar($storage);
$this->updateFile($storage);
$this->unlockFile();
$this->closeFile();
}
/**
* gets the current cache/session for a giving $key
*
* #param string $key
* #return object or boolean
*/
public function getCache($key)
{
$value = false;
$this->openFile();
$storage = $this->readFile();
if(isset($storage[$key])){
$value = $storage[$key];
}
$this->closeFile();
return $value;
}
/**
* removes the $id from the cache/session
*
* #param string $key
* #param bigint $id
* #return boolean
*/
public function removeCache($key, $id)
{
$this->openFile();
$this->lockFile();
$storage = $this->readFile();
if( !isset($storage[$key][$id])){
$this->unlockFile();
$this->closeFile();
return false;
}
unset($storage[$key][$id]);
$this->updateFile($storage);
$this->unlockFile();
$this->closeFile();
return true;
}
/**
* unset a session
*
* #param argument $keys
* #return void
*/
public function truncateCache()
{
if(file_exists($this->filename)){
unlink($this->filename);
}
}
/**
* Open a file in a giving mode
*
* #params string $mode
* #return void
*/
private function openFile( $mode = "w+"){
$this->handle = fopen($this->filename, $mode);
if(!$this->handle){
throw new exception('The File could not be opened!');
}
}
/**
* Close the file
* #return void
*/
private function closeFile(){
fclose($this->handle);
$this->handle = null;
}
/**
* Update the file with array data
* #param array $data the array in that has the data
* #return void
*/
private function updateFile(array $data = array() ){
$raw = serialize($data);
fwrite($this->handle, $raw);
}
/**
* Read the data from the opned file
*
* #params string $mode
* #return array of the data found in the file
*/
private function readFile() {
$length = filesize($this->filename);
if($length > 0){
rewind($this->handle);
$raw = fread($this->handle, filesize($this->filename));
return unserialize($raw);
}
return array();
}
/**
* Lock the file
*
* #return void
*/
private function lockFile( $maxAttempts = 100, $lockType = LOCK_EX) {
$i = 0;
while($i <= $maxAttempts){
// acquire an exclusive lock
if( flock($this->handle, LOCK_EX) ){
break;
}
++$i;
}
}
/**
* Unlock the file
*
* #return void
*/
private function unlockFile() {
fflush($this->handle);
flock($this->handle, LOCK_UN);
}
/**
* Remove add cache files
*
* #return void
*/
private function collectGarbage(){
$mydir = dirname($this->filename);
$dir = new DirectoryIterator( $mydir );
$time = strtotime("now");
foreach ($dir as $file) {
if ( !$file->isDot()
&& $file->isFile()
&& ($time - $file->getATime()) > $this->maxTimeAllowed
&& isset($file->getFilename) && $file->getFilename != 'index.html'
) {
unlink($file->getPathName());
}
}
}
}
This is how I call my class
<?php
require 'autoloader.php';
try {
$cache = new \ICWS\CacheHandler('cache/12300000');
$field = array('name' => 'Mike A', 'Address' => '123 S Main', 'phone' => '2152456245', 'ext' => 123);
$cache->updateCache('NewKey', '123456', $field);
echo '<pre>';
print_r($cache->getCache('NewKey'));
echo '</pre>';
} catch (exception $e){
echo $e->getMessage();
}
?>
When commenting the line print_r($cache->getCache('NewKey')); The file 12300000 will have the data below as expected
a:1:{s:6:"NewKey";a:1:{i:123456;O:8:"stdClass":4:{s:4:"name";s:6:"Mike A";s:7:"Address";s:10:"123 S Main";s:5:"phone";s:10:"2152456245";s:3:"ext";i:123;}}}
However, when the method print_r($cache->getCache('NewKey')); is called the file becomes empty.
What am I doing wrong here? Why is my print_r($cache->getCache('NewKey')); method is emptying out the file?
openFile($mode = "w+")
The documentation for fopen() says:
'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
So it resets the file, deleting everything in it.
Probably you want mode a+:
'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does not exist, attempt to create it. In this mode, fseek()() only affects the reading position, writes are always appended.
When i open https://127.0.0.1/mutillidae/ then my webpage show this error
I also change the permission of LoggerAppenderFile.php but it still error.
The php file code is
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* #package log4php
* #subpackage appenders
*/
/**
* FileAppender appends log events to a file.
*
* Parameters are ({#link $fileName} but option name is <b>file</b>),
* {#link $append}.
*
* #version $Revision: 806678 $
* #package log4php
* #subpackage appenders
*/
class LoggerAppenderFile extends LoggerAppender {
/**
* #var boolean if {#link $file} exists, appends events.
*/
private $append = true;
/**
* #var string the file name used to append events
*/
protected $fileName;
/**
* #var mixed file resource
*/
protected $fp = false;
public function __construct($name = '') {
parent::__construct($name);
$this->requiresLayout = true;
}
public function __destruct() {
$this->close();
}
public function activateOptions() {
$fileName = $this->getFile();
if(!is_file($fileName)) {
$dir = dirname($fileName);
if(!is_dir($dir)) {
mkdir($dir, 0777, true);
}
}
$this->fp = fopen($fileName, ($this->getAppend()? 'a':'w'));
if($this->fp) {
if(flock($this->fp, LOCK_EX)) {
if($this->getAppend()) {
fseek($this->fp, 0, SEEK_END);
}
fwrite($this->fp, $this->layout->getHeader());
flock($this->fp, LOCK_UN);
$this->closed = false;
} else {
// TODO: should we take some action in this case?
$this->closed = true;
}
} else {
$this->closed = true;
}
}
public function close() {
if($this->closed != true) {
if($this->fp and $this->layout !== null) {
if(flock($this->fp, LOCK_EX)) {
fwrite($this->fp, $this->layout->getFooter());
flock($this->fp, LOCK_UN);
}
fclose($this->fp);
}
$this->closed = true;
}
}
public function append(LoggerLoggingEvent $event) {
if($this->fp and $this->layout !== null) {
if(flock($this->fp, LOCK_EX)) {
fwrite($this->fp, $this->layout->format($event));
flock($this->fp, LOCK_UN);
} else {
$this->closed = true;
}
}
}
/**
* Sets and opens the file where the log output will go.
*
* This is an overloaded method. It can be called with:
* - setFile(string $fileName) to set filename.
* - setFile(string $fileName, boolean $append) to set filename and append.
*/
public function setFile() {
$numargs = func_num_args();
$args = func_get_args();
if($numargs == 1 and is_string($args[0])) {
$this->setFileName($args[0]);
} else if ($numargs >=2 and is_string($args[0]) and is_bool($args[1])) {
$this->setFile($args[0]);
$this->setAppend($args[1]);
}
}
/**
* #return string
*/
public function getFile() {
return $this->getFileName();
}
/**
* #return boolean
*/
public function getAppend() {
return $this->append;
}
public function setAppend($flag) {
$this->append = LoggerOptionConverter::toBoolean($flag, true);
}
public function setFileName($fileName) {
$this->fileName = $fileName;
}
/**
* #return string
*/
public function getFileName() {
return $this->fileName;
}
}
How can i solve this problem ?
I found a solution in http://fanli7.net/a/bianchengyuyan/PHP/20130723/398120.html here but i failed. If this problem is unsolvable then it can occur a big problem for my lab testing ?
OK. I find the solution. Actually you setup a old version of mutillidae. So it was buggy program. Then i find a new version. Here is the download link enter link description here. After you setup it,it will be awesome.