FAQ

Build your own S3 file storage

Amazon's S3 is an amazing system, but for many use-cases it is overkill. We developed a light-weight version which allows to offload the images / media to another location. 

This free's up resources on your server and by not embedding large files in your database your database will run very fast and efficient.







# 1 > Setup

the setup is simple, we just need a few variables which are defined globally. 

Using cakePHP our global variables are defined in bootstrap.php - Add the following lines:

 

    Configure::write('ImageStorage.domain', 'http://img.YourDomain.com'); 

    Configure::write('ImageStorage.security', 'HardToGuessCodeGoesHere348878q3h2387y298rhskjfhwoeir8uyq938ru');

 

NOTE: You must have full control over ImageStorage.domain
-> You will be uploading files to this server





# 2 > AppController: HandleFiles

Add this function to your AppController
-> This will be called when you upload an image using the normal image uploader

 

public function handleFiles($model) {

//model is bucket
//name is the ID
$security = Configure::read('ImageStorage.security');
$domain = Configure::read('ImageStorage.domain');

//get the extension
$info = pathinfo($this->request->data[$model]['File']['name']);
$obj_extension = $info['extension'];

//ensure no weird characters
$obj_key = urlencode($this->request->data['ProductPic']['id']);
$obj_bucket = $model;
$obj_blob = file_get_contents($this->request->data[$model]['File']['tmp_name']);

# Our new data
$data = array(
'key' => $obj_key,
'ext' => $obj_extension,
'bucket' => $obj_bucket,
'data' => urlencode($obj_blob)
);

# Create a connection
$url = $domain.'/'.'files_put.php';

$ch = curl_init($url);
# Form data string
$postString = http_build_query($data, '', '&');
# Setting our options
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('security:'.$security));
# Get the response
$response = curl_exec($ch);
curl_close($ch);

//pr ($response);

if ($response != '200') {
die ('problem uploading');
}
}




# 3 > REMOTE server: files_put.php

Place this on the remote server
-> This will accept connections from your code and add the files to the local filesystem 

<?php
/////PUT
$security = 'YourSecretGoesHere343434387487348378';
if (isset($_SERVER['HTTP_SECURITY'])) {
if ($_SERVER['HTTP_SECURITY'] == $security) {
if (!file_exists($_POST['bucket'])) {
mkdir($_POST['bucket'], 0777, true);
}

file_put_contents('access-PUT.log', 'Uploaded: ' . $_SERVER['HTTP_HOST'].' '.$_POST['bucket'] . '/' . $_POST['key'] . '.' . $_POST['ext']."\n", FILE_APPEND);
file_put_contents($_POST['bucket'] . '/' . $_POST['key'] . '.' . $_POST['ext'], urldecode($_POST['data']));

die("200");
} else {
//unauthorized access
file_put_contents('error-PUT.log', 'bad password: ' . $_SERVER['HTTP_HOST']);
die("404");
}
} else {
file_put_contents('error-PUT.log', 'unknown access: ' . $_SERVER['HTTP_HOST']);
die("404");
}




# 4 > REMOTE server: files-get.php

Place this file on your remote server
-> This will accept connections and return back the files/images that exist can be used in your local code

 

<?php
/////PUT
$security = 'YourSecretGoesHere3489934892859348394582934823ij';
$bucket = $_POST['bucket'];
$domain = $_POST['domain'];



$exclude = array(
'.','..'
);

file_put_contents('access-GET.log', json_encode($_SERVER)."\n", FILE_APPEND);

if (isset($_SERVER['HTTP_SECURITY'])) {
if ($_SERVER['HTTP_SECURITY'] == $security) {
if (!file_exists($bucket)) {
die('404: bucket does not exist');
} else {
//file_put_contents('access-GET.log', 'Bucket Exists: ' . $_SERVER['HTTP_HOST'].' '.$_POST['bucket'] . '/' . $_POST['key']."\n", FILE_APPEND);

$files = array_diff(scandir($bucket), $exclude);
//print_r ($files);
$array = array();
foreach ($files as $file) {

$info = pathinfo($bucket.'/'.$file);
//print_r ($info);

if (!isset($array[ $bucket ])) {
$array[ $bucket ] = array();
}
if (!isset($array[ $bucket ][ $info['filename'] ])) {
$array[ $bucket ][ $info['filename'] ] = array();
}
$array[ $bucket ][ $info['filename'] ] = $info;

//setup the path
$array[ $bucket ][ $info['filename'] ]['path'] = $domain.'/'.$bucket.'/'.$file;
}
//print_r ($array);
//die('Found');
echo json_encode($array);
exit;
}
} else {
//unauthorized access
file_put_contents('error-GET.log', 'bad password: ' . $_SERVER['HTTP_HOST']);
}
} else {
file_put_contents('error-GET.log', 'unknown access: ' . $_SERVER['HTTP_HOST']);
}




# 5 > Helper-ImageStorage

Create a Helper, which will be used to retrieve all the files/images from your remote server

<?php class ImageStorageHelper {

var $results = false;

// function getAllBuckets() {
//
// }
function getByBucket($obj_bucket) {


//we already did it in this session, so let's NOT use up bandwidth to do it again
if (!empty($response)) {
$this->results = json_decode($response, true);
return $this->results;
}


$security = Configure::read('ImageStorage.security');
$domain = Configure::read('ImageStorage.domain');
//$obj_bucket = "ProductPic";
//$obj_key = "name";

# Create a connection
$url = $domain.'/'.'files_get.php';

# Our new data
$data = array(
'bucket' => $obj_bucket,
'domain' => $domain
);
$ch = curl_init($url);
# Form data string
$postString = http_build_query($data, '', '&');
# Setting our options
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('security:'.$security));
# Get the response
$response = curl_exec($ch);
curl_close($ch);

//pr ($response);exit;

if (!empty($response)) {
$this->results = json_decode($response, true);
return $this->results;
}


}

function getImageByName($obj_bucket, $obj_name) {
$info = $this->getByBucket($obj_bucket);
if (isset($info[$obj_bucket])) {
if (isset($info[ $obj_bucket ][ $obj_name ])) {
return $info[$obj_bucket][$obj_name]['path'];
}
}
//does not exist
return false;


}

function getImageTagByName($obj_bucket, $obj_name, $width = false, $height = false) {
$name = $this->getImageByName($obj_bucket, $obj_name);

if (!empty($name)) {
$tag = "<img src='";
$tag .= $name;
$tag .= "' ";

if ($width) {
$tag .= " width='".$width."px'";
}
if ($height) {
$tag .= " height='".$height."px'";
}

$tag .= "/>";

return $tag;
}
}


function afterRenderFile() {

}

function afterRender() {

}

function beforeLayout() {

}

function beforeRenderFile() {

}

function afterLayout() {

}

}




# 6 > GetImage

To retrieve an image do the following

$model is normally the model being used, but it can be any unique bucket name, or way to organize

$name this is the file name, normally we connect this with the ID in a database, so you can connect databases to media/image very easily and efficiently 

 

<?= $this->ImageStorage->getImageTagByName($model, $name, 150); ?>