Codeigniter Image uploading not working on live server - mysql

I have a situation where a user uploads his/her trip photos. They are saved in a folder and also supposed to be in database. Situation is: my code is working perfectly on localhost, and many other servers, but not on the server I want. Though it uploads files successfully, but the query is not executed which is supposed to save file path in database. I am stuck in this problem from more than a week. The same code works in other places. Here is my controller:
public function trip_photos(){
$this->load->model('UserModel');
$this->load->model('CommentModel');
$this->load->library('session');
print_r($_FILES);
$logged_session = $this->session->userdata('login');
if($logged_session == 1) {
$this->load->model('TripModel');
$this->load->model('UserActivityModel');
$uid = $this->session->userdata('uid');
$tid = $this->input->post('tid');
foreach($_FILES as $key => $image_upload){
$upload = self::upload_trip_photo($key);
if($upload['status']){
$this->TripModel->add_trip_photo($uid, $tid, $upload['file']);
}
}
$this->UserctivityModel->add_user_photo($uid, $tid);
}else{
redirect('/');
}
}
private function upload_trip_photo($image){
$msg = '';
$config['upload_path'] = './assets/images/trip/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 2048;
$config['file_name'] = parent::getGUID();
$this->load->library('upload', $config);
if ($this->upload->do_upload($image))
{
$data = $this->upload->data();
$resize['image_library'] = 'gd2';
$resize['source_image'] = "./assets/images/trip/" . $data['file_name'];
$resize['create_thumb'] = TRUE;
$resize['maintain_ratio'] = TRUE;
$resize['width'] = 222;
$resize['thumb_marker'] = '';
$resize['new_image'] = "./assets/images/trip/thumbnails/" . $data['file_name'];
$this->image_lib->resize();
$this->image_lib->clear();
$this->image_lib->initialize($resize);
if($this->image_lib->resize()){
$status = true;
$msg = $data['file_name'];
}else{
$status = false;
}
}
else
{
$status = false;
}
#unlink($_FILES[$image]);
return array('status' => $status, 'file' => $msg);
}
when I enabled CI_Profiler, it says that only 2 out of 3 query executed on the server I want it to work. But the same profiler suggests that 3 of 3 queries executed on localhost or other servers. Its so confusing.
Please note that I already have checked the following:
File Upload: On
upload_raw_post_data: On
selinux permissions: disables (mine is centos)
File permissions: 777
php memory_limit: 128 MB
max_size: 8 MB
var_dump, print_r, echo all not working or displaying any information from controller.
somehow, this in above code: $upload = self::upload_trip_photo($key); is not giving it back the file path it requires. Can anybody help please? #DFriend
UPDATED Turns out that in the localhost are other servers where its working, this array is returned by the function upload_trip_photo to the $upload variable:
Array ( [image0] => Array ( [name] => maintour3.jpg [type] => image/jpeg
[tmp_name] => D:\xampp\tmp\php2539.tmp [error] => 0 [size] => 200491 ) )
array(2) { ["status"]=> bool(true) ["file"]=> string(36)
"E3965DFC8B265CEFF522A1EC43B33E34.jpg" }
while in the server where its not working, only this array is returned:
Array ( [image0] => Array ( [name] => mg7.jpg [type] => image/jpeg
[tmp_name] => /tmp/phpNcCnX0 [error] => 0 [size] => 28460 ) )
It means this statement in the upload_trip_photo() function:
return array('status' => $status, 'file' => $msg);
is not returning the requested array, with file name and status. And why? I am totally clueless.
Help Please!

Thankfully this worked after extensive debugging. The line
if($this->image_lib->resize()){
$status = true;
$msg = $data['file_name'];
}else{
$status = false;
}
was not working. Later when I set it to display_error() method, it showed that my server did not support GD library. This is an essential library to manipulate Graphics. So, the query was not being executed, as the $status variable was set to false.
I recompiled my php with GD Library module. And bigno! its working now.
Thanks for staying with me. :)

Related

Create custom url links in code igniter

I have searched all over the internet for information that would help me achieve this seemingly simple thing.
But I can't get my hands on any that is helpful.
What I want to do is to create a custom url link like http://mywebsite.com/users/username,
where
1) 'users' is a MySQL table name
2) 'username' is a column name.
I did some digging on the internet and found this code on github:
<?php
//check for referal links
function referal()
{
$CI =& get_instance();
$cookie_value_set = $CI->input->cookie('_tm_ref', TRUE) ? $CI->input->cookie('_tm_ref', TRUE) : '';
if ($CI->input->get('ref', TRUE) AND $cookie_value_set == '') {
// referred user so set cookie to ref=username
$cookie = array(
'name' => 'ref',
'value' => $CI->input->get('ref', TRUE),
'expire' => '7776000',
);
$CI->input->set_cookie($cookie);
return TRUE;
}elseif ($cookie_value_set == '') {
$cookie = array(
'name' => 'ref',
'value' => 'sso',
'expire' => '15552000',
);
$CI->input->set_cookie($cookie);
return TRUE;
}elseif ($cookie_value_set != '') {
//already referred so ignore
return TRUE;
}else{
return TRUE;
}
}
//end of hooks file
?>
The owner of the gist only mentioned saving the file as referral.php inside the hook folder. This is not helping me with what I want to achieve, I don't know how to use the code:
1. How do I pass the referrer field to the variable username from the users table?
2. How do I load the hook file to view (register.php)?
3. How and where do I call the hook file?
So can anybody give me an insight?

How can I see hidden app data in Google Drive?

I have an Android app that stores my notes in hidden app data. I want to export my notes so the question is simple:
How can I access the hidden app data in Google Drive for a specific app?
Indeed, Google does not let you access this hidden app-data folder directly.
But, if you can get your hands on the app's client ID/client secret/digital signature that is used for authentication against Google's servers - then yes, you can basically emulate the app and access the hidden data in your Google Drive using the Drive API.
How it works in Android
Usually, when an android application wants to access a Google API (such as Drive, Games or Google Sign-In - not all are supported) it communicates with the Google Play services client library, which in turn obtains an access token from Google on behalf of the app. This access token is then sent with each request to the API, so that Google knows who is using it and what he is allowed to do with your account (OAuth 2.0). In order to get this access token for the first time, the Google Play service sends an HTTPS POST request to android.clients.google.com/auth with these fields (along with other details):
Token - a "master token" which identifies the Google account and basically allows full access to it
app - the application package name, such as com.whatsapp
client_sig - the application's digital signature (sent as SHA1)
device - the device's Android ID
service - the scopes (permissions) that the app wants to have
So before we can start using the Drive API in the name of a specific app, we need to know its signature and our account's master token. Fortunately, the signature can be easily extracted from the .apk file:
shell> unzip whatsapp.apk META-INF/*
Archive: whatsapp.apk
inflating: META-INF/MANIFEST.MF
inflating: META-INF/WHATSAPP.SF
inflating: META-INF/WHATSAPP.DSA
shell> cd META-INF
shell> keytool -printcert -file WHATSAPP.DSA # can be CERT.RSA or similar
.....
Certificate fingerprints:
SHA1: 38:A0:F7:D5:05:FE:18:FE:C6:4F:BF:34:3E:CA:AA:F3:10:DB:D7:99
Signature algorithm name: SHA1withDSA
Version: 3
The next thing we need is the master token. This special token is normally received and stored on the device when a new google account is added (for example, when first setting up the phone), by making a similar request to the same URL. The difference is that now the app that's asking for permissions is the Play services app itself (com.google.android.gms), and Google is also given additional Email and Passwd parameters to log in with. If the request is successful, we will get back our master token, which could then be added to the user's app request.
You can read this blogpost for more detailed information about the authentication process.
Putting it all together
Now, we can write a code for authentication using these two HTTP requests directly - a code that can browse any app's files with any Google account. Just choose your favorite programming language and client library. I found it easier with PHP:
require __DIR__ . '/vendor/autoload.php'; // Google Drive API
// HTTPS Authentication
$masterToken = getMasterTokenForAccount("your_username#gmail.com", "your_password");
$appSignature = '38a0f7d505fe18fec64fbf343ecaaaf310dbd799';
$appID = 'com.whatsapp';
$accessToken = getGoogleDriveAccessToken($masterToken, $appID, $appSignature);
if ($accessToken === false) return;
// Initializing the Google Drive Client
$client = new Google_Client();
$client->setAccessToken($accessToken);
$client->addScope(Google_Service_Drive::DRIVE_APPDATA);
$client->addScope(Google_Service_Drive::DRIVE_FILE);
$client->setClientId(""); // client id and client secret can be left blank
$client->setClientSecret(""); // because we're faking an android client
$service = new Google_Service_Drive($client);
// Print the names and IDs for up to 10 files.
$optParams = array(
'spaces' => 'appDataFolder',
'fields' => 'nextPageToken, files(id, name)',
'pageSize' => 10
);
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0)
{
print "No files found.\n";
}
else
{
print "Files:\n";
foreach ($results->getFiles() as $file)
{
print $file->getName() . " (" . $file->getId() . ")\n";
}
}
/*
$fileId = '1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0';
$content = $service->files->get($fileId, array('alt' => 'media' ));
echo var_dump($content);
*/
function getGoogleDriveAccessToken($masterToken, $appIdentifier, $appSignature)
{
if ($masterToken === false) return false;
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$requestedService = 'oauth2:https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file';
$data = array('Token' => $masterToken, 'app' => $appIdentifier, 'client_sig' => $appSignature, 'device' => $deviceID, 'google_play_services_version' => '8703000', 'service' => $requestedService, 'has_permission' => '1');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while requesting an access token: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Auth=") + strlen("Auth=");
$endsAt = strpos($result, "\n", $startsAt);
$accessToken = substr($result, $startsAt, $endsAt - $startsAt);
return "{\"access_token\":\"" . $accessToken . "\", \"refresh_token\":\"TOKEN\", \"token_type\":\"Bearer\", \"expires_in\":360000, \"id_token\":\"TOKEN\", \"created\":" . time() . "}";
}
function getMasterTokenForAccount($email, $password)
{
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$data = array('Email' => $email, 'Passwd' => $password, 'app' => 'com.google.android.gms', 'client_sig' => '38918a453d07199354f8b19af05ec6562ced5788', 'parentAndroidId' => $deviceID);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while trying to log in: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Token=") + strlen("Token=");
$endsAt = strpos($result, "\n", $startsAt);
$token = substr($result, $startsAt, $endsAt - $startsAt);
return $token;
}
And finally, the results -
Files:
gdrive_file_map (1d9QxgC3p4PTXRm_fkAY0OOuTGAckykmDfFls5bAyE1rp)
Databases/msgstore.db.crypt9 (1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0)
16467702039-invisible (1yHFaxfmuB5xRQHLyRfKlUCVZDkgT1zkcbNWoOuyv1WAR)
Done.
NOTE: This is an unofficial, hacky solution, and so it might have a few problems. For example, the access token is alive only for one hour, after which it won't be refreshed automatically.
A working example as of September 2020
Note: this is actually an addition for Tomer's answer
Things changed since Tomer's original answer was posted.
Currently, to get the master token and avoid the Error=BadAuthentication, you need two things:
Replace Passwd field with EncryptedPasswd and encrypt its value by RSA with google public key (the exact technique was reversed by some guy) - this can be done using phpseclib.
Make HTTPS connection to Google server with the same SSL/TLS options as in one of the supported Android systems. This includes TLS versions and exact list of supported ciphers in right order. If you change the order or add/remove ciphers you'll get Error=BadAuthentication. It took me a whole day to figure this out...
Luckily, PHP >=7.2 comes with openssl-1.1.1 that has all the necessary ciphers to emulate Android 10 client.
So here is rewriten getMasterTokenForAccount() function that sets the ciphers and uses EncryptedPasswd instead of plain Passwd. And below is encryptPasswordWithGoogleKey() implementation that does the encryption.
phpseclib is necessary and can be installed with composer: composer require phpseclib/phpseclib:~2.0
function getMasterTokenForAccount($email, $password)
{
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$data = array('Email' => $email, 'EncryptedPasswd' => encryptPasswordWithGoogleKey($email, $password), 'app' => 'com.google.android.gms', 'client_sig' => '38918a453d07199354f8b19af05ec6562ced5788', 'parentAndroidId' => $deviceID);
$options = array(
'ssl' => array(
'ciphers' => 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS'),
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while trying to log in: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Token=") + strlen("Token=");
$endsAt = strpos($result, "\n", $startsAt);
$token = substr($result, $startsAt, $endsAt - $startsAt);
return $token;
}
function encryptPasswordWithGoogleKey($email, $password)
{
define('GOOGLE_KEY_B64', 'AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pKRI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/6rmf5AAAAAwEAAQ==');
$google_key_bin = base64_decode(GOOGLE_KEY_B64);
$modulus_len = unpack('Nl', $google_key_bin)['l'];
$modulus_bin = substr($google_key_bin, 4, $modulus_len);
$exponent_len = unpack('Nl', substr($google_key_bin, 4 + $modulus_len, 4))['l'];
$exponent_bin = substr($google_key_bin, 4 + $modulus_len + 4, $exponent_len);
$modulus = new phpseclib\Math\BigInteger($modulus_bin, 256);
$exponent = new phpseclib\Math\BigInteger($exponent_bin, 256);
$rsa = new phpseclib\Crypt\RSA();
$rsa->loadKey(['n' => $modulus, 'e' => $exponent], phpseclib\Crypt\RSA::PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(phpseclib\Crypt\RSA::ENCRYPTION_OAEP);
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
$encrypted = $rsa->encrypt("{$email}\x00{$password}");
$hash = substr(sha1($google_key_bin, true), 0, 4);
return strtr(base64_encode("\x00{$hash}{$encrypted}"), '+/', '-_');
}
The user cannot directly access data in the hidden app folders, only the app can access them. This is designed for configuration or other hidden data that the user should not directly manipulate. (The user can choose to delete the data to free up the space used by it.)
The only way the user can get access to it is via some functionality exposed by the specific app.
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
to get all the file in app data try the code
private void listFiles() {
Query query =
new Query.Builder()
.addFilter(Filters.or(Filters.eq(SearchableField.MIME_TYPE, "text/html"),
Filters.eq(SearchableField.MIME_TYPE, "text/plain")))
.build();
getDriveResourceClient()
.query(query)
.addOnSuccessListener(this,
new OnSuccessListener<MetadataBuffer>() {
#Override
public void onSuccess(MetadataBuffer metadataBuffer) {
//mResultsAdapter.append(metadataBuffer);
for (int i = 0; i <metadataBuffer.getCount() ; i++) {
retrieveContents(metadataBuffer.get(i).getDriveId().asDriveFile());
}
}
}
)
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Error retrieving files", e);
MainActivity.this.finish();
}
});
}
also you can download the content of file bye the following code
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}

Creating and filling database from a Controller (Symfony 2, Doctrine)

I am trying to create an installation Bundle for my Symfony 2.2.3 application.
Therefore I want to drop/create a database (mysql) and then create the schema via Controller Actions.
My Code:
$kernel = $this->get('kernel');
$application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
$application->setAutoExit(false);
// drop old database
$options = array('command' => 'doctrine:database:drop', '--force' => true);
$application->run(new \Symfony\Component\Console\Input\ArrayInput($options));
// create new database
$options = array('command' => 'doctrine:database:create');
$result = $application->run(new \Symfony\Component\Console\Input\ArrayInput($options));
// check if database:create was successful, then create schema
if($result == 0) {
$options = array('command' => 'doctrine:schema:create');
$result = $application->run(new \Symfony\Component\Console\Input\ArrayInput($options));
}
database:drop and database:create work fine (both commands return 0), but creating the schema then fails.
However, when I comment the first 2 commands out so that only doctrine:schema:create will be executed (if clause removed, of course) and reload the page without changing anything else the database schema will be created properly.
Can anyone tell me what the problem is?
This code works (Symfony 2.7)
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
/**
* #Route("/resetDB", name="adminResetDB")
*/
public function resetDBAction()
{
$application = new Application($this->get('kernel'));
$application->setAutoExit(false);
// Drop old database
$options = array('command' => 'doctrine:database:drop', '--force' => true);
$application->run(new ArrayInput($options));
// Make sure we close the original connection because it lost the reference to the database
$this->getDoctrine()->getManager()->getConnection()->close();
// Create new database
$options = array('command' => 'doctrine:database:create');
$application->run(new ArrayInput($options));
// Update schema
$options = array('command' => 'doctrine:schema:update','--force' => true);
$application->run(new ArrayInput($options));
// Loading Fixtures, --append option prevent confirmation message
$options = array('command' => 'doctrine:fixtures:load','--append' => true);
$application->run(new ArrayInput($options));
return $this->redirect($this->generateUrl('index'));
}

How to force download a .csv file in Symfony 2, using Response object?

I'm making a "Download" controller using Symfony 2, that has the sole purpose of sending headers so that I can force a .csv file download, but it isn't working properly.
$response = new Response();
$response->headers->set('Content-Type', "text/csv");
$response->headers->set('Content-Disposition', 'attachment; filename="'.$fileName.'"');
$response->headers->set('Pragma', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($fileName));
$response->prepare();
$response->sendHeaders();
$response->setContent(readfile($fileName));
$response->sendContent();
$fileName is a "info.csv" string. Such are my actions inside my controller, there's no return statement. When I tried returning the Response Object, the contents of the file were displayed in the browser, not my intended result.
The problem I've found is that in some pages I do get my info.csv file, but in anothers all I get is a message:
No webpage was found for the web address: http://mywebpage.com/download
Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.
I'm completely sure the file exists, so there must be another thing wrong. Also, routing.yml is working correctly, since I do get the file from other pages that also link to that path.
The Apache error log doesn't show anything about it.
Has anyone forced the download of a .csv file on Symfony 2 before? If so, what am I doing wrong?
Here is a minimal example that works just fine in production:
class MyController
public function myAction()
$response = $this->render('ZaysoAreaBundle:Admin:Team/list.csv.php',$tplData);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="teams.csv"');
return $response;
You can replace the render call with new response and response->setContent if you like.
Your comment about no return statement inside a controller is puzzling. Controllers return a response. Let the framework take care of sending the stuff to the browser.
I realize this post is kind of old and that there is, oddly enough, practically no good resources on how to do a CSV Export in symfony 2 besides this post at stackoverflow.
Anyways I used the example above for a client contest site and it worked quite well. But today I received an e-mail and after testing it myself, the code had broken - I was able to get the download working with a small amount of results, but the database now exporting over 31,000 rows it either simply showed the text or with chrome, just basically did nothing.
For anyone having issue with a large data export, this is what I manged to get to work, basically doing what Cerad suggested as an alternate way:
$filename = "export_".date("Y_m_d_His").".csv";
$response = $this->render('AppDefaultBundle:Default:csvfile.html.twig', array('data' => $data));
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Description', 'Submissions Export');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
$response->prepare();
$response->sendHeaders();
$response->sendContent();
EDIT: After more testing and upping the max seconds allowed, I realized the previous code was printing out the headers at the top so I've updated the code.
THis worked for me to export CSV and JSON.
Twig files are named : export.csv.twig, export.json.twig
The Controller :
class PrototypeController extends Controller {
public function exportAction(Request $request) {
$data = array("data" => "test");
$format = $request->getRequestFormat();
if ($format == "csv") {
$response = $this->render('PrototypeBundle:Prototype:export.' . $format . '.twig', array('data' => $data));
$filename = "export_".date("Y_m_d_His").".csv";
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
return $response;
} else if ($format == "json") {
return new Response(json_encode($data));
}
}
}
The Routing :
prototype_export:
pattern: /export/{_format}
defaults: { _controller: PrototypeBundle:Prototype:export, _format: json }
requirements:
_format: csv|json
The Twigs:
export.csv.twig (do your comma seperated thing here, this is just a test)
{% for row in data %}
{{ row }}
{% endfor %}
export.json.twig (data is sent json_encoded, this file is empty)
Hope this helps!
This is how I managed to get Silex to return a csv:
// $headers in an array of strings
// $results are the records returned by a PDO query
$stream = function() use ($headers, $results) {
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($results as $rec)
{
fputcsv($output, $rec);
}
fclose($output);
};
return $app->stream($stream, 200, array(
'Content-Type' => 'text/csv',
'Content-Description' => 'File Transfer',
'Content-Disposition' => 'attachment; filename="test.csv"',
'Expires' => '0',
'Cache-Control' => 'must-revalidate',
'Pragma' => 'public',
));
You may also need to do some Jiggery Pokery with Javascript (I was downloading Via AJAX) but this post was all I needed to get it working.
simple function you can use for every case to export an csv for download...
public function getResponse(array $data, $filename, $headers = array())
{
if(substr(strtolower($filename), -4) == '.csv') {
$filename = substr($filename, 0, -4);
}
$tmpFile = $this
->_getContainer()
->get('kernel')
->getRootDir()
. '/../var/tmp_'.substr(md5(time()),0,5);
if(file_exists($tmpFile)) unlink($tmpFile);
$handle = fopen($tmpFile, 'w');
foreach ($data as $i => $row) {
$row = (array) $row;
if($i == 0) fputcsv($handle, array_keys($row));
fputcsv($handle, $row);
}
fclose($handle);
$Response = new Response(file_get_contents($tmpFile));
unlink($tmpFile);
$filename = preg_replace('[^a-z0-9A-Z_]', '', $filename);
$headers = array_merge([
'Expires' => 'Tue, 01 Jul 1970 06:00:00 GMT',
'Cache-Control' => 'max-age=0, no-cache, must-revalidate, proxy-revalidate',
'Content-Disposition' => 'attachment; filename='.$filename.'.csv',
'Content-Type' => 'text/csv',
'Content-Transfer-Encoding' => 'binary',
], $headers);
foreach ($headers as $key => $val) {
$Response->headers->set($key, $val);
}
return $Response;
}
How about using Sonata's Exporter:
use Exporter\Writer\CsvWriter;
/**
* #param array $orders
*/
public function exportToCsv($orders)
{
$rootdir = $this->get('kernel')->getRootDir();
$filename = $rootdir . '/data/orders.csv';
unlink($filename);
$csvExport = new CsvWriter($filename);
$csvExport->open();
foreach ($orders as $order)
{
$csvExport->write($order);
}
$csvExport->close();
return;
}
It crashes if the file already exists, thus the unlink-command.

Upload and Insert File Data in CodeIgniter

I'm creating a file upload system in CodeIgniter, and I have a form that asks for a file name before it uploads to the database. It uses my controller to upload the file to the server. Currently the controller is working, but I need to insert the file name into the table.
upload.php:
function do_upload()
{
$config['upload_path'] = './gfiles/';
$config['allowed_types'] = 'gif|jpg|jpeg|bmp|png|psd|pdf|eps|ai|zip|indd|qxt';
$config['encrypt_name'] = 'TRUE';
//$config['max_size'] = '100';
$this->load->library('upload', $config);
if ( ! $this->upload->do_upload())
{
$error = array('error' => $this->upload->display_errors());
$this->load->view('upload', $error);
}
else
{
$data = array('upload_data' => $this->upload->data());
$this->db->insert('files', $_POST);
}
}
Does anyone have any pointers on how to get the file name into the database properly? The code above also encrypts the filename. Thank you.
$data = array('upload_data' => $this->upload->data()); should contain what you are looking for.
do print_r($data) and you should see the original and encrypted filename.