PHP File Upload - Custom Upload - problem with dbClean and with editor display of image
PHP File Upload - Custom Upload - problem with dbClean and with editor display of image
 raphiw90            
            
                Posts: 7Questions: 3Answers: 0
raphiw90            
            
                Posts: 7Questions: 3Answers: 0            
            Hi everyone
I am building an expense tracker with an editor instance where a user can enter information like date, description, amount, currency and via an upload field the user can directly upload a photo of the receipt. I have used the custom upload so that I can manipulate the image and reduce the file size. That all works smoothly but I have two issues:
1) the dbClean function is not working and it seems that the "system_path" cannot be read
Error:
<br/>
<b>Notice</b>
:  Undefined index: system_path in 
<b>/app/assets/php/table.expenses.php</b>
 on line 
<b>103</b>
<br/>
<br/>
<b>Warning</b>
:  unlink() [
<a href='https://secure.php.net/manual/en/function.unlink.php'>function.unlink.php</a>
]: No such file or directory in 
<b>app/assets/php/table.expenses.php</b>
 on line 
<b>103</b>
<br/>
{"data":[]}
2) the little thumbnail of the uploaded file in the editor instance called via "display": function (id) {
return '<img src="' + editor.file('receipts', id ).web_path + '"/>'; also returns undefined (respectively the ? symbol).


I don't know exactly how to approach it so that I can get the right data, any ideas? Below the JS and PHP code -> sorry can't give access to a live try & error page or reproduce the error in a test case...
Thanks a lot for your time & help!
Raphael
(function ($) {
  $(document).ready(function () {
    var editor = new $.fn.dataTable.Editor({
      ajax: 'assets/php/table.expenses.php',
      table: '#expenses',
      fields: [{
          "label": "Guide:",
          "name": "expenses.guide_id",
          "type": "select",
          "placeholder": "Select a Guide"
        },
        {
          "type": "checkbox",
          "label": "Income?",
          "name": "expenses.income",
          "options": [{
            label: "",
            value: 1,
          }],
          "sparator": '',
          "unselectedValue": 0,
          "attr": {
            disabled: true
          }
        },
        {
          "label": "Date of the expense:",
          "name": "expenses.date",
          "type": "datetime",
          "format": "DD\/MM\/YY"
        },
        {
          "label": "Description:",
          "name": "expenses.description"
        },
        {
          "label": "Amount:",
          "name": "expenses.amount",
          "fieldInfo": "Important: use . (not ,) for amounts with cents e.g. 1.15 CHF",
          "attr": {
            type: 'number'
          }
        },
        {
          "label": "Currency",
          "name": "expenses.currency",
          "type": "select",
          "placeholder": "Select a type",
          "options": [{
              label: "EUR",
              value: "EUR"
            },
            {
              label: "CHF",
              value: "CHF"
            },
          ]
        },
        {
          "label": "Receipt:",
          "name": "expenses.receipt",
          "type": "upload",
          "display": function (id) {
            return '<img src="' + editor.file('receipts', id ).web_path + '"/>';
          },
          "clearText": "Clear",
          "noImageText": 'No receipt scanned!'
        },
      ]
    });
    var table = $('#expenses').DataTable({
      dom: 'Blfrtip',
      ajax: 'assets/php/table.expenses.php',
      columns: [{
          "data": null,
          "render": function (data, type, row) {
            return data.accounts.first_name + ' ' + data.accounts.last_name
          }
        },
        {
          "data": "expenses.date"
        },
        {
          "data": "expenses.description"
        },
        {
          "data": null,
          "render": function (data, type, row) {
            if (data.expenses.income == 0) {
              pref = "-"
            } else {
              pref = "+"
            }
            return pref + ' ' + data.expenses.amount + ' ' + data.expenses.currency
          }
        },
        {
          "data": "receipts.web_path",
            defaultContent: "No receipt scanned!"
        },
      ],
      select: true,
      colReorder: true,
      buttons: [{
          extend: 'create',
          editor: editor
        },
        {
          extend: 'edit',
          editor: editor
        },
        {
          extend: 'remove',
          editor: editor
        },
        {
          extend: 'collection',
          text: 'Export',
          buttons: [
            'copy',
            'excel',
            'csv',
            'pdf',
            'print'
          ]
        }
      ],
    });
    //Reloads the "Wallet" table automatically when a change is made.
    editor.on('submitSuccess', function (e, json, data, action) {
      $('#wallet').DataTable().ajax.url('assets/php/table.wallet.php').load();
    });
    $("tbody", "#expenses").on("click", "td:eq(4)",
      function () {
        window.open(this.innerText);
      });
  });
}(jQuery));
<?php
session_start();
 // Create an array to hold variables to be used in the closure function.
  $varArray = [
  "id" => $_SESSION[ 'id' ], //includes Guide ID to backtrack changes
  "username" => $_SESSION[ 'username' ], //includes Username to rename files
];
// DataTables PHP library and database connection
include( "lib/DataTables.php" );
// Editor Classes
use
    DataTables\Editor,
    DataTables\Editor\Field,
    DataTables\Editor\Format,
    DataTables\Editor\Mjoin,
    DataTables\Editor\Options,
    DataTables\Editor\Upload,
    DataTables\Editor\Validate,
    DataTables\Editor\ValidateOptions;
// Editor Instance
Editor::inst( $db, 'expenses', 'id' )
    ->fields(
        Field::inst( 'expenses.guide_id' )
            ->options( Options::inst()
                ->table( 'accounts' )
                ->value( 'id' )
                ->label( 'username' )
                     )
            ->validator( Validate::dbValues() )
            ->validator( Validate::notEmpty() ),
        Field::inst( 'accounts.username' ),
        Field::inst( 'accounts.first_name' ),
        Field::inst( 'accounts.last_name' ),
        Field::inst( 'expenses.date' )
            ->validator( Validate::dateFormat( 'd/m/y' ) )
            ->getFormatter( Format::datetime( 'Y-m-d', 'd/m/y' ) )
            ->setFormatter( Format::datetime( 'd/m/y', 'Y-m-d' ) )
            ->validator( Validate::notEmpty() ),
        Field::inst( 'expenses.income' )
            ->validator (Validate::notEmpty())
            ->setFormatter( Format::implode(",")),
        Field::inst ('expenses.description')
            ->validator( Validate::notEmpty() ),
        Field::inst( 'expenses.amount' )
            ->validator( Validate::notEmpty() ),
        Field::inst( 'expenses.currency' )
            ->validator( Validate::notEmpty() ),
        Field::inst( 'expenses.receipt' )
            
            ->setFormatter( Format::ifEmpty( "" ) )
 
                ->upload(
                  Upload::inst( function ( $file, $id )use( $varArray, $db ) {
                    // Cuts the image info into pieces for further manipulation
                    $receipt = $varArray[ "username" ] . "_" . $file[ 'name' ];
                    $tmpname = $file[ 'tmp_name' ];
                    $filename = pathinfo( $receipt, PATHINFO_FILENAME );
                    $extension = pathinfo( $receipt, PATHINFO_EXTENSION );
                    $filename_orig = $filename;
                    
                    // Checks if the file already exsits and if so adds an increment at the end
                    $num = 1;
                    while ( file_exists( $_SERVER[ 'DOCUMENT_ROOT' ] . '/app/assets/images/receipts/' . $receipt ) ) {
                      $filename = ( string )$filename_orig . $num;
                      $receipt = $filename . "." . $extension;
                      $num++;
                    }
                    $target = $_SERVER[ 'DOCUMENT_ROOT' ] . '/app/assets/images/receipts/' . $receipt;
                    //Imagick coverts image and reduces filesize
                    $compreceipt = new Imagick( $file[ 'tmp_name' ] );
                    $compreceipt->setImageFormat( $extension );
                    $compreceipt->resizeImage( 800, 500, Imagick::FILTER_LANCZOS, 1, true );
                    $compreceipt->setImageCompressionQuality( 50 );
                    $compreceipt->writeImage( $target );
                    
                    //Update Database with new info
                    $db->update(
                      'receipts', [
                        "filename" => $receipt,
                        "web_path" => '/app/assets/images/receipts/' . $receipt,
                        "system_path" => $target,
                      ], [ "id" => $id ]
                    );
                    return $id;
                      
                  } )
                    ->db( 'receipts', 'id', array(
                    'guide_id' => $varArray[ "id" ],
                  ) )
                    
                    ->dbClean( function ( $data ) use ($db) {
                // Remove the files from the file system
                for ( $i=0, $ien=count($data) ; $i<$ien ; $i++ ) {
                    unlink( $data[$i]['system_path'] );
                }
 
                // Have Editor remove the rows from the database
                return true;
            } )
                ->validator( Validate::fileExtensions( array( 'png', 'jpg', 'jpeg', 'gif' ), "Please upload an image" ) )
                ),
    
    
            Field::inst( 'receipts.web_path' )
    )
    ->leftJoin( 'accounts',     'accounts.id',                  '=', 'expenses.guide_id' )
    ->leftJoin( 'receipts',     'receipts.id',                  '=', 'expenses.receipt' )
    ->process( $_POST )
    ->json();
This question has an accepted answers - jump to answer
Answers
Hi,
1) You don't have
system_pathin your->db(...)call for theUploadinstance, so it won't be automatically populated into the data array.print_r($data);there should confirm this.Either you need to add it into that array, or query the database for the system path information for the files to be deleted.
2) Likewise,
web_pathisn't in the->db(...)call so that information isn't populated and available on the client-side. Adding it in should resolve that error as well.Allan
Thanks Allan, I'll have a look!