What could be stopping the server for send a valid response?

261 views Asked by At

This question is related to this one and I tough the issue was fixed but surprisingly is not. I'll write the same code again (I've removed comments and pieces of code, this is just a general example) just for make this post understandable.

Currently this is the code I have in a Zend Framework 1 controller:

public function uploadAction()
{
    $this->_helper->viewRenderer->setNoRender();
    $data = $errors = $line_of_text = [];

    if ($this->getRequest()->isPost()) {
        $path = '/cronjobs/uploads/charge_type_details';

        if (!@mkdir($path, 0777, true) && !is_dir($path)) {
            $data['error'][] = "Not able to create subdirectory: <strong>{$path}</strong>";
            echo json_encode($data);

            die();
        }

        $di = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
        $ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($ri as $file) {
            $file->isDir() ? rmdir($file) : unlink($file);
        }

        $adapter = new Zend_File_Transfer_Adapter_Http();
        $adapter->setDestination($path);
        $adapter->addValidator('Extension', false, ['extension' => 'csv', 'case' => true]);
        $adapter->addValidator('MimeType', false, 'text/plain');
        $adapter->addValidator('Size', false, ['max' => ini_get('upload_max_filesize').'B']);

        if ($adapter->isValid() === false) {
            foreach ($adapter->getMessages() as $message) {
                $data['error'][] = $message;
            }

            echo json_encode($data);

            die();
        }

        $file     = $adapter->getFileInfo()['file'];
        $ext      = pathinfo($file['name'])['extension'];
        $new_path = $file['tmp_name'];

        $file_handle = fopen($new_path, 'r');

        while (($result = fgetcsv($file_handle)) !== false) {
            if (array(null) !== $result) { // ignore blank lines
                $line_of_text[] = $result;
            }
        }

        $unique_rows = array_unique($line_of_text, SORT_REGULAR);

        if (false === $this->isFileHeadersValid(
                array_map('strtolower', $unique_rows[0]),
                [
                    'country',
                    'charge_type',
                    'charge_type_code',
                    'business_sla_description',
                    'service_provider',
                    'sub_menu',
                    'charge_type_group',
                    'transaction_type',
                    'slc_code',
                    'coverage_code',
                    'standard_sla',

                ]
            )
        ) {
            $data['error'][] = $this->translate->_('Required file headers are not present. Please check the file and try again.');
            echo json_encode($data);

            die();
        }

        unset($unique_rows[0]);

        $data['error'] = $errors;

        $data['file'] = array(
            'name'     => $file['name'],
            'size'     => $adapter->getFileSize(),
            'file_ext' => $ext
        );
    } else {
        $data['error'] = 'Invalid request.';
    }

    echo json_encode($data);

    die();
}

That function is being called by Javascript as an AJAX function:

$('#fileupload').show().fileupload({
    url: '/upload',
    cache: false,
    dataType: 'json',
    done: function (e, data) {
       if (data.result.error.length > 0) {
           // process errors here
        } else {
           // do something here
        }
    }
})

I am uploading a file with about 1.5 MB of size and having around 9000 rows (it's a CSV file).

As soon as I upload that file everything seems to be working and this mean the code execution on PHP side goes until the last echo json_encode($data); without "errors". I did know this because I am using Xdebug to debug the code on the IDE.

For some reason the response is not coming back to the browser and I end up with the following message: "Failed to load response" and I am not able to process the response properly.

enter image description here

enter image description here

enter image description here

I did checked the result of json_encode($data) by assigning it to a var and everything seems to be fine as per this output (the filenames on the images and this example are different but this is only for shown proper functionality):

{
  "error": [],
  "file": {
    "name": "test1.csv",
    "size": "1.24kB",
    "file_path": "/data/tmp/php/uploads/phpSh2tZt",
    "file_ext": "csv",
    "delimiter": "",
    "worksheets": []
  }
}

I have checked the process in Chrome and Firefox and there is no Status on the response sent as you might see on the images above. Why? I don't know what else to do in order to fix this, I don't know where the error is coming from (it's not from PHP code because as I said all works properly at code level and logs said so) and I am stuck at this point, can any give me some ideas or clue about this?

My environment is running in Docker if that helps.

The PHP setup is as follow:

memory_limit = 2048M
post_max_size = 128M
upload_max_filesize = 128M
date.timezone = UTC
max_execution_time = 120
short_open_tag=On
serialize_precision=100
session.gc_maxlifetime=7200
session.entropy_length=0

PS: if you need any kind of information let me know and I'll add it to the OP

UPDATE

I just found out where the problem might be and I am curious about the "why". Having the following piece of code:

$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($path);
$adapter->addValidator('Extension', false, ['extension' => 'csv', 'case' => true]);
$adapter->addValidator('MimeType', false, 'text/plain');
$adapter->addValidator('Size', false, ['max' => ini_get('upload_max_filesize').'B']);

if ($adapter->isValid() === false) {
    foreach ($adapter->getMessages() as $message) {
        $data['error'][] = $message;
    }

    echo json_encode($data);

    die();
}

Makes the complete code to fails by getting the non response on the browser. Moving away the validation makes the code to work properly:

$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($path);

What could possibly be wrong there? I am missing something here?

UPDATE 2

This is currently how the code looks like:

....
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($path);
$adapter->addValidator('Extension', false, ['extension' => 'csv', 'case' => true]);
$adapter->addValidator('MimeType', false, ['text/plain', 'text/csv']);
$adapter->addValidator('Size', false, ['max' => $this->SizeToBytes(ini_get('upload_max_filesize'))]);

if ($adapter->receive() === false || $adapter->isValid() === false) {
    foreach ($adapter->getMessages() as $message) {
        $data['error'][] = $message;
    }

    echo json_encode($data);

    return true;
}
....
private function SizeToBytes($val)
{
    $val  = trim($val);
    $last = strtolower($val[strlen($val) - 1]);
    switch ($last) {
        case 'g':
            $val *= 1024;
        case 'm':
            $val *= 1024;
        case 'k':
            $val *= 1024;
    }

    return $val;
}

This doesn't work either. The only way I got this to work was moving to "vanilla" PHP as follow:

// Validate file mimetype
if (!in_array($adapter->getMimeType(), ['text/plain', 'text/csv'])) {
    $data['error'][] = $this->translate->_('File is not valid only CSV files are accepted!');
    echo json_encode($data);

    return true;
}

// Validate file extension
if ($ext !== 'csv') {
    $data['error'][] = $this->translate->_('File extension is not valid only CSV files are accepted!');
    echo json_encode($data);

    return true;
}

// Validate file size depending on php.ini upload_max_filesize configuration
$max = $this->SizeToBytes(ini_get('upload_max_filesize'));
if ($file['size'] > $max) {
    $data['error'][] = $this->translate->_e('File size is not valid! The size should be less than: ').ini_get('upload_max_filesize').'B';
    echo json_encode($data);

    return true;
}

This way it works like a charm.

3

There are 3 answers

0
segFault On

You are using a much smaller max size (128 bytes) than you intended.

You should convert your ini defined upload_max_filesize to the full integer value (~128000000).

For example:

$adapter->addValidator('Size', false, ['max' => 128000000]);
1
Hossam On

Regarding the Status & the "why":

I think using http_response_code(200) at the page processing ajax response may help.

1
Honk der Hase On

Shouldn't you call "$adapter->receive()" somewhere?

https://framework.zend.com/manual/1.11/en/zend.file.transfer.introduction.html

$adapter = new Zend_File_Transfer_Adapter_Http();

$adapter->setDestination('C:\temp');

if (!$adapter->receive()) {
    $messages = $adapter->getMessages();
    echo implode("\n", $messages);
}