<?php
class Mail{
private $image_box;
public $count = 0;
public $zipper;
$encoding = "base64";
$type = "image/png";
public function __construct(){
$this->turnToImage();
}
public function addToObject($object_name, $object_data){
//save to object
// $object_name : $object_data
}
public function turnToImage(){
$this->image_box = $_POST['canvas_data'];
foreach($this->image_box as $img)
{
$this->count++;
$data = substr($img, strpos($img, ","));
$image_name ="OrderImg".$this->count.".png";
$this->addToObject($image_name, $data);
}
}
public function toZip(){
}
}
$Mail = new Mail();
?>
i have canvas fabric image data , and i want to decode to image and zip it up and send by mail.
so 1st question is how do i save the my data to object and be like this ?
object{
$object_name1 : object_data1,
$object_name2 : object_data2
}
2nd how do i zip them up ? after i store to object and some how zip them up together as one zip file ? i am stucked here.
Related
im using modal bootstrap with codeignitter 4. I can delete the data in database but cannot unlink the image. here my code :
Model :
public function deleteProduct($id)
{
$query = $this->db->table('produk')->delete(array('kode' => $id));
return $query;
}
Controller :
public function delete()
{
$model = new produkModel();
$id = $this->request->getPost('kode');
$produk = $this->produkModel->find($id);
if ($produk['gambar'] != 'default.png') {
unlink('imgproduk/' . $produk['gambar']);
}
$model->deleteProduct($id);
return redirect()->to('/Tabel_Produk');
}
i want to delete the image in directory but dont delete the default.img
Use complete folder path to delete/access image through PHP by using $_SERVER['DOCUMENT_ROOT'] to get server path.
public function delete(){
$model = new produkModel();
$id = $this->request->getPost('kode');
$produk = $this->produkModel->find($id);
if ($produk['gambar'] != 'default.png') {
unlink($_SERVER['DOCUMENT_ROOT'].'/imgproduk/' . $produk['gambar']);
}
$model->deleteProduct($id);
return redirect()->to('/Tabel_Produk');
}
I'm developing an api on which it gets an image and resizes it into three sizes and zips it. I have some methods to validate the file, run the resizer class and its methods and finally give files as zip file and a link to download them. Now I have problem with content type validation and zipping. I searched a lot and I couldn't find any tutorial. I'd be thankful if you help me with my errors.
rest.php
<?php
require_once 'constants.php';
abstract class Rest
{
public array $request;
public array $errors = [];
public function __construct()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->throwError(REQUEST_METHODS_NOT_VALID, 'Request method is not valid.');
}
$this->request = $_FILES + $_POST;
$fileName = $_FILES['image']['name'];
$fileType = $_FILES['image']['type'];
$this->validateRequest($fileName);
if (empty($this->errors)){
$this->executeApi();
}
$this->response();
}
public abstract function validateRequest($request);
public abstract function executeApi();
public function validateParameters($fieldName, $value, $dataType, $required) {
}
public function throwError($code, $message) {
header("content-type: application/json");
$errorMsg = json_encode(['error'=>['status'=>$code, 'message'=>$message]]);
echo $errorMsg;
exit();
}
public function response() {
//???
}
}
api.php
<?php
require_once 'image-resizer.php';
class Api extends Rest
{
public function validateRequest($request)
{
// if ($request !== 'image/jpeg') {
if ($_SERVER['CONTENT_TYPE'] !== 'image/jpeg') {
$this->throwError(REQUEST_CONTENT_TYPE_NOT_VALID, 'Request content type is not valid.');
$errors = json_encode(array("message" => "Request content type is not valid.", "status" => false));
echo $errors;
}
json_decode($request, true);
}
public function executeApi()
{
$source = $this->request['image'];
$resize = new Resizer();
$resize->imageResizer($source);
}
}
getimagesize is not to be used to validate a file as image
$imgsize = getimagesize($sourceFile);
$srcWidth = $imgsize[0];
$srcHeight = $imgsize[1];
$mime = $imgsize['mime'];
you can use: fileinfo
OR you may validate extension using pathinfo
$allowedExt = ['jpg', 'jpeg', 'png'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowedExt)) {
return FALSE;
}
// filesize validation
if (filesize($tmpName) > MAX_FILE_SIZE) {
}
check more on filesize
Edit:
You may check this link for zipping files with PHP
EDIT:
$this->request = $_FILES + $_POST; // this is insecure way to get the data
check $_POST data sanitization
what is a good method to sanitize the whole $_POST array in php?
I have a script when user can clip video, then that video uploads to public folder, and now I want to upload all video data to database. But i get error like in title. Here's my code:
Controller:
public function clip($id)
{
$video = Video::where('id', $id)->first();
$oldId = $video->id;
$originalName = $video->original_name;
$newName = str_random(50) . '.' . 'mp4';
FFMpeg::fromDisk('public')
->open('/uploads/videos/' .$video->file_name)
->addFilter(function ($filters) {
$filters->clip(FFMpeg\Coordinate\TimeCode::fromSeconds(5), FFMpeg\Coordinate\TimeCode::fromSeconds(2));
})
->export()
->toDisk('public')
->inFormat(new \FFMpeg\Format\Video\X264)
->save('/uploads/videos/' . $newName);
$data = ['user_id'=>Auth::user()->id,
'file_name'=>$newName,
'original_name'=> $originalName,
'old_id' => $oldId,
];
$video = Video::edit($data);
}
Model:
public static function edit($request)
{
$video = new Video;
$video->user_id = $request->user_id;
$video->file_name = $request->file_name;
$video->original_name = $request->original_name;
$video->save();
$old = $file = Video::where('id', $request->old_id)->delete();
//$old_file = unlink($request->file('file'));
return $video;
}
What should I edit?
Since you're passing array, you need to use $request['user_id'] syntax instead $request->user_id. You're getting the error because you're trying to treat the array as an object.
But since you have prepared array here, just use create method:
public static function edit($data)
{
$this->destroy($data['old_id']);
return $this->create($data);;
}
Don't forget to add $fillable array to your model to make it work.
Below example of 'store' method of my controller Admin/MoviesController. It already seems quite big, and 'update' method will be even bigger.
The algoritm is:
Validate request data in CreateMovieRequest and create new movie
with all fillable fields.
Upload poster
Fill and save all important, but not required fields (Meta title, Meta Description..)
Then 4 blocks of code with parsing and attaching to movie of Genres, Actors, Directors, Countries.
Request of IMDB's rating using third-party API
My questions:
Should I just move all this code to Model and divide it into smaller methods like: removeGenres($id), addGenres(Request $request), ...
Are there some best practices? I'm talking not about MVC, but Laravel's features. At the moment to keep some logic behind the scene I'm using only Request for validation.
public function store(CreateMovieRequest $request) {
$movie = Movies::create($request->except('poster'));
/* Uploading poster */
if ($request->hasFile('poster')) {
$poster = \Image::make($request->file('poster'));
$poster->fit(250, 360, function ($constraint) {
$constraint->upsize();
});
$path = storage_path() . '/images/movies/'.$movie->id.'/';
if(! \File::exists($path)) {
\File::makeDirectory($path);
}
$filename = time() . '.' . $request->file('poster')->getClientOriginalExtension();
$poster->save($path . $filename);
$movie->poster = $filename;
}
/* If 'Meta Title' is empty, then fill it with the name of the movie */
if ( empty($movie->seo_title) ) {
$movie->seo_title = $movie->title;
}
/* If 'Meta Description' is empty, then fill it with the description of the movie */
if ( empty($movie->seo_description) ) {
$movie->seo_description = $movie->description;
}
// Apply all changes
$movie->save();
/* Parsing comma separated string of genres
* and attaching them to movie */
if (!empty($request->input('genres'))) {
$genres = explode(',', $request->input('genres'));
foreach($genres as $item) {
$name = mb_strtolower(trim($item), 'UTF-8');
$genre = Genre::where('name', $name)->first();
/* If such genre doesn't exists in 'genres' table
* then we create a new one */
if ( empty($genre) ) {
$genre = new Genre();
$genre->fill(['name' => $name])->save();
}
$movie->genres()->attach($genre->id);
}
}
/* Parsing comma separated string of countries
* and attaching them to movie */
if (!empty($request->input('countries'))) {
$countries = explode(',', $request->input('countries'));
foreach($countries as $item) {
$name = mb_strtolower(trim($item), 'UTF-8');
$country = Country::where('name', $name)->first();
if ( empty($country) ) {
$country = new Country();
$country->fill(['name' => $name])->save();
}
$movie->countries()->attach($country->id);
}
}
/* Parsing comma separated string of directors
* and attaching them to movie */
if (!empty($request->input('directors'))) {
$directors = explode(',', $request->input('directors'));
foreach($directors as $item) {
$name = mb_strtolower(trim($item), 'UTF-8');
// Actors and Directors stored in the same table 'actors'
$director = Actor::where('fullname', trim($name))->first();
if ( empty($director) ) {
$director = new Actor();
$director->fill(['fullname' => $name])->save();
}
// Save this relation to 'movie_director' table
$movie->directors()->attach($director->id);
}
}
/* Parsing comma separated string of actors
* and attaching them to movie */
if (!empty($request->input('actors'))) {
$actors = explode(',', $request->input('actors'));
foreach($actors as $item) {
$name = mb_strtolower(trim($item), 'UTF-8');
$actor = Actor::where('fullname', $name)->first();
if ( empty($actor) ) {
$actor = new Actor();
$actor->fill(['fullname' => $name])->save();
}
// Save this relation to 'movie_actor' table
$movie->actors()->attach($actor->id);
}
}
// Updating IMDB and Kinopoisk ratings
if (!empty($movie->kinopoisk_id)) {
$content = Curl::get('http://rating.kinopoisk.ru/'.$movie->kinopoisk_id.'.xml');
$xml = new \SimpleXMLElement($content[0]->getContent());
$movie->rating_kinopoisk = (double) $xml->kp_rating;
$movie->rating_imdb = (double) $xml->imdb_rating;
$movie->num_votes_kinopoisk = (int) $xml->kp_rating['num_vote'];
$movie->num_votes_imdb = (int) $xml->imdb_rating['num_vote'];
$movie->save();
}
return redirect('/admin/movies');
}
You need to think on how you could re-utilize the code if you need to use it in another classes or project modules. For starting, you could do something like this:
Movie model, can improved in order to:
Manage the way on how the attributes are setted
Create nice functions in functions include/manage the data of relationships
Take a look how the Movie implements the functions:
class Movie{
public function __construct(){
//If 'Meta Title' is empty, then fill it with the name of the movie
$this->seo_title = empty($movie->seo_title)
? $movie->title
: $otherValue;
//If 'Meta Description' is empty,
//then fill it with the description of the movie
$movie->seo_description = empty($movie->seo_description)
? $movie->description
: $anotherValue;
$this->updateKinopoisk();
}
/*
* Parsing comma separated string of countries and attaching them to movie
*/
public function attachCountries($countries){
foreach($countries as $item) {
$name = mb_strtolower(trim($item), 'UTF-8');
$country = Country::where('name', $name)->first();
if ( empty($country) ) {
$country = new Country();
$country->fill(['name' => $name])->save();
}
$movie->countries()->attach($country->id);
}
}
/*
* Update Kinopoisk information
*/
public function updateKinopoisk(){}
/*
* Directors
*/
public function attachDirectors($directors){ ... }
/*
* Actores
*/
public function attachActors($actors){ ... }
/*
* Genders
*/
public function attachActors($actors){ ... }
}
Poster, you may considere using a service provider (I will show this example because I do not know your Poster model
looks like):
public class PosterManager{
public static function upload($file, $movie){
$poster = \Image::make($file);
$poster->fit(250, 360, function ($constraint) {
$constraint->upsize();
});
$path = config('app.images') . $movie->id.'/';
if(! \File::exists($path)) {
\File::makeDirectory($path);
}
$filename = time() . '.' . $file->getClientOriginalExtension();
$poster->save($path . $filename);
return $poster;
}
}
Config file
Try using config files to store relevant application constanst/data, for example, to store movie images path:
'images' => storage_path() . '/images/movies/';
Now, you are able to call $path = config('app.images'); globally. If you need to change the path only setting the config file is necessary.
Controllers as injected class.
Finally, the controller is used as a class where you only need to inject code:
public function store(CreateMovieRequest $request) {
$movie = Movies::create($request->except('poster'));
/* Uploading poster */
if ($request->hasFile('poster')) {
$file = $request->file('poster');
$poster = \PosterManager::upload($file, $movie);
$movie->poster = $poster->filename;
}
if (!empty($request->input('genres'))) {
$genres = explode(',', $request->input('genres'));
$movie->attachGenders($genders);
}
// movie->attachDirectors();
// movie->attachCountries();
// Apply all changes
$movie->save();
return redirect('/admin/movies');
}
I am generating a pdf from the mPDF library using the Yii framework. For this PDF I need to add charts generated on the server, so I'm using the pChart library to generate them. I created a simple object class to set the pChart properties in an easier way for the PDF.
This is the class object:
<?php
Class Chart {
protected $fontsFolder = null;
protected $data = array();
protected $resolution = array();
public $chartType = null;
public $fontSize = 18;
public $displayValues = false;
public $dirFile = null;
function __construct() {
Yii::import('application.vendors.pChart.class.*', true);
$this->fontsFolder = Yii::getPathOfALias('application.vendors.pChart.fonts');
}
// Set data points
public function data($data) {
if(!isset($data))
throw new CException('Data array missing');
if(!is_array($data))
throw new CException('Data must be an array');
$this->data[] = $data;
}
// Set label points
public function labels($labels) {
if(!isset($labels))
throw new CException('Labels data must be assgined');
if(!is_array($labels))
throw new CException('Labels data must be an array');
if(isset($this->data['labels']))
throw new CException('Labels data is already assigned');
$this->data['labels'] = $labels;
}
// Set resolution image
public function resolution($x, $y) {
if(isset($x) && isset($y)) {
if(is_array($x) && is_array($y))
throw new CException('Array to String error');
$this->resolution['x'] = $x;
$this->resolution['y'] = $y;
} else
throw new CException('Resolution data missing');
}
public function Debug() {
var_dump($this->fontsFolder, $this->data, $this->resolution);
}
// Render chart with given data
public function renderChart() {
if(!$this->data)
throw new CException('Data property must be assigned');
if(!$this->resolution)
throw new CException('Resolution property must be assigned');
if(!$this->chartType)
throw new CException('Chart type cannot be null');
if(!$this->dirFile)
throw new CException('Directory file must be assigned');
$this->render();
}
protected function render() {
switch ($this->chartType) {
case 'lineChart':
$this->lineChart();
break;
default:
throw new CEXception('"'.$this->chartType.'" is not a valid chart type');
break;
}
}
protected function lineChart() {
include('pDraw.class.php');
include('pImage.class.php');
include('pData.class.php');
$data = new pData();
foreach($this->data as $key => $value) {
if(is_int($key))
$data->addPoints($value);
}
$data->addPoints($this->data['labels'], 'labels');
$data->setAbscissa('labels');
$picture = new pImage($this->resolution['x'], $this->resolution['y'], $data);
$picture->setFontProperties(array('FontName'=>$this->fontsFolder.'/Forgotte.ttf'), $this->fontSize);
$picture->setGraphArea(60, 40, 970, 190);
$picture->drawScale(array(
'GridR'=>200,
'GridG'=>200,
'GridB'=>200,
'DrawXLines'=>false
));
$picture->drawLineChart(array('DisplayValues'=>$this->displayValues));
$picture->render($this->dirFile);
}
}
?>
And here is how I'm instantiating the object with PDF settings:
<?php
Class SeguimientoController extends Controller {
// public $layout = '//layouts/column2';
public function actionIndex() {
// Cargar libreria pdf y estilos
$mPDF = Yii::app()->ePdf->mpdf();
$mPDF->debug = true;
$mPDF->showImageErrors = true;
$stylesheet = file_get_contents(Yii::getPathOfAlias('webroot.css.reporte') . '/main.css');
$mPDF->WriteHTML($stylesheet, 1);
// Generate first chart
$chart = new Chart;
$chart->data(array(1,2,3,4,5));
$chart->Labels(array('asd', 'dead', 'eads', 'daed', 'fasd'));
$chart->resolution(1000, 200);
$chart->chartType = 'lineChart';
$chart->displayValues = true;
$chart->dirFile = Yii::getPathOfAlias('webroot.images').'/chart.png';
$chart->renderChart();
$mPDF->WriteHTml(CHtml::image('/basedato1/images/chart.png', 'chart'), 2);
// Generate second chart
$chart1 = new Chart;
$chart1->data(array(1,2,3,4,5));
$chart1->Labels(array('asd', 'dead', 'eads', 'daed', 'fasd'));
$chart1->resolution(1000, 200);
$chart1->chartType = 'lineChart';
$chart1->displayValues = true;
$chart1->dirFile = Yii::getPathOfAlias('webroot.images').'/chart.png';
$chart1->renderChart();
$mPDF->WriteHTml(CHtml::image('/basedato1/images/chart.png', 'chart'), 2);
$mPDF->OutPut();
}
}
?>
By testing the output of the view step by step, everything goes fine, the chart is rendered and saved as a temp file so the pdf can gather it. But when I have to render the second chart, I get a fatal error.
I have tried creating another class to be accessed by static functions because I thought the error could be made from multiple instances of the same object. But again, on second render I get the same error.
Just in case, if you need to know how the error outputs, here it is: Fatal error: Cannot redeclare class pDraw in C:\Servidor\basedato1\protected\vendors\pChart\class\pDraw.class.php on line 104.
Use include_once instead of include.
include_once('pDraw.class.php');
include_once('pImage.class.php');
include_once('pData.class.php');