1

I tried different approach but still can't find the solution.

I need to upload an image with my form with fields (title, description, and 2 image).

My system uses csrf of CodeIgniter. And I use this simple third party file uploader (http://jasny.github.io/bootstrap) fileinput.js

                var Fileinput = function (element, options) {
                this.$element = $(element)

                this.$input = this.$element.find(':file')
                if (this.$input.length === 0) return

                this.name = this.$input.attr('name') || options.name

                this.$hidden = this.$element.find('input[type=hidden][name="' + this.name + '"]')
                if (this.$hidden.length === 0) {
                  this.$hidden = $('<input type="hidden">').insertBefore(this.$input)
                }

                this.$preview = this.$element.find('.fileinput-preview')
                var height = this.$preview.css('height')
                if (this.$preview.css('display') !== 'inline' && height !== '0px' && height !== 'none') {
                  this.$preview.css('line-height', height)
                }

                this.original = {
                  exists: this.$element.hasClass('fileinput-exists'),
                  preview: this.$preview.html(),
                  hiddenVal: this.$hidden.val()
                }

                this.listen()
              }

              Fileinput.prototype.listen = function() {
                this.$input.on('change.bs.fileinput', $.proxy(this.change, this))
                $(this.$input[0].form).on('reset.bs.fileinput', $.proxy(this.reset, this))

                this.$element.find('[data-trigger="fileinput"]').on('click.bs.fileinput', $.proxy(this.trigger, this))
                this.$element.find('[data-dismiss="fileinput"]').on('click.bs.fileinput', $.proxy(this.clear, this))
              },

              Fileinput.prototype.change = function(e) {
                var files = e.target.files === undefined ? (e.target && e.target.value ? [{ name: e.target.value.replace(/^.+\\/, '')}] : []) : e.target.files

                e.stopPropagation()

                if (files.length === 0) {
                  this.clear()
                  return
                }

                this.$hidden.val('')
                this.$hidden.attr('name', '')
                this.$input.attr('name', this.name)

                var file = files[0]

                if (this.$preview.length > 0 && (typeof file.type !== "undefined" ? file.type.match(/^image\/(gif|png|jpeg)$/) : file.name.match(/\.(gif|png|jpe?g)$/i)) && typeof FileReader !== "undefined") {
                  var reader = new FileReader()
                  var preview = this.$preview
                  var element = this.$element

                  reader.onload = function(re) {
                    var $img = $('<img>')
                    $img[0].src = re.target.result
                    files[0].result = re.target.result

                    element.find('.fileinput-filename').text(file.name)

                    // if parent has max-height, using `(max-)height: 100%` on child doesn't take padding and border into account
                    if (preview.css('max-height') != 'none') $img.css('max-height', parseInt(preview.css('max-height'), 10) - parseInt(preview.css('padding-top'), 10) - parseInt(preview.css('padding-bottom'), 10)  - parseInt(preview.css('border-top'), 10) - parseInt(preview.css('border-bottom'), 10))

                    preview.html($img)
                    element.addClass('fileinput-exists').removeClass('fileinput-new')

                    element.trigger('change.bs.fileinput', files)
                  }

                  reader.readAsDataURL(file)
                } else {
                  this.$element.find('.fileinput-filename').text(file.name)
                  this.$preview.text(file.name)

                  this.$element.addClass('fileinput-exists').removeClass('fileinput-new')

                  this.$element.trigger('change.bs.fileinput')
                }
              },

              Fileinput.prototype.clear = function(e) {
                if (e) e.preventDefault()

                this.$hidden.val('')
                this.$hidden.attr('name', this.name)
                this.$input.attr('name', '')

                //ie8+ doesn't support changing the value of input with type=file so clone instead
                this.$input.val('')

                this.$preview.html('')
                this.$element.find('.fileinput-filename').text('')
                this.$element.addClass('fileinput-new').removeClass('fileinput-exists')

                if (e !== undefined) {
                  this.$input.trigger('change')
                  this.$element.trigger('clear.bs.fileinput')
                }
              },

              Fileinput.prototype.reset = function() {
                this.clear()

                this.$hidden.val(this.original.hiddenVal)
                this.$preview.html(this.original.preview)
                this.$element.find('.fileinput-filename').text('')

                if (this.original.exists) this.$element.addClass('fileinput-exists').removeClass('fileinput-new')
                 else this.$element.addClass('fileinput-new').removeClass('fileinput-exists')

                this.$element.trigger('reset.bs.fileinput')
              },

              Fileinput.prototype.trigger = function(e) {
                this.$input.trigger('click')
                e.preventDefault()
              }


              // FILEUPLOAD PLUGIN DEFINITION
              // ===========================

              var old = $.fn.fileinput

              $.fn.fileinput = function (options) {
                return this.each(function () {
                  var $this = $(this),
                      data = $this.data('bs.fileinput')
                  if (!data) $this.data('bs.fileinput', (data = new Fileinput(this, options)))
                  if (typeof options == 'string') data[options]()
                })
              }

              $.fn.fileinput.Constructor = Fileinput


              // FILEINPUT NO CONFLICT
              // ====================

              $.fn.fileinput.noConflict = function () {
                $.fn.fileinput = old
                return this
              }


              // FILEUPLOAD DATA-API
              // ==================

              $(document).on('click.fileinput.data-api', '[data-provides="fileinput"]', function (e) {
                var $this = $(this)
                if ($this.data('bs.fileinput')) return
                $this.fileinput($this.data())

                var $target = $(e.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]');
                if ($target.length > 0) {
                  e.preventDefault()
                  $target.trigger('click.bs.fileinput')
                }
              });

Now here is my form:

    <form id="default_form" onsubmit="return false;" data-method="websites" enctype="multipart/form-data" data-toastr-position="top-right" data-success="Sent! Thank you!"  class="validate" novalidate="novalidate">
    <input type="hidden" name="{$my_csrf_name}"  id="csrf" value="{$my_csrf_value}" />
    <input type="text" class="form-control required" value="" name="d[DEF_TITLE]" id="MY_TITLE">
    <textarea class="form-control required" rows="3" name="d[MY_DESC]" id="MY_DESC"></textarea>
    <div class="fileinput fileinput-new" data-provides="fileinput">
        <div class="fileinput-new thumbnail" style="min-width: 160px; min-height: 100px; max-width: 200px; max-height: 150px; line-height: 10px;"> <img src="{$_homeurl}space/perm/img/favicon/{$set_data.MY_FAVICON}" alt="{$homeurl}space/perm/img/favicon/{$set_data.MY_FAVICON}" data-src="{$homeurl}space/perm/img/favicon/{$set_data.MY_FAVICON}" > </div>
        <div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 150px;"></div>
        <div> 
            <span class="btn btn-default btn-file" class="upload-image">
            <span class="fileinput-new">Select Favicon image</span>
            <span class="fileinput-exists">Change</span>
            <input type="file" id="MY_FAVICON" name="d[MY_FAVICON]"></span> 
            <a href="#" class="btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a> 
        </div>
    </div>
    <button id="submit_form" data-fid="default_form" class="btn btn-3d btn-primary btn-xlg btn-block margin-top-30" type="submit">
        SUBMIT
    </button>
</form>

Now upon clicking the "Select Favicon image" here is my js code event:

    var csrf_val = $('#csrf').val();
    var csfrData = {};
    csfrData['csrf_name'] = csrf_val;
    sendFile(this.files[0]);
    function sendFile(file) {
        $(function() {
            $.ajaxSetup({
               data: csfrData
            });
        });
        $.ajax({
            method: 'post',
            url: _admin_url + _curr_mod+'/procedure/uload-image',
            data: file,
            success: function() {
                alert('upload is ok!');
            },
            processData: false
        });
    }

upon select of image the JavaScript will process to upload the image in PHP controller/model. As I try to look into the Firebug the post has this values:

ÿØÿà�JFIF������ÿÛ��

Then in the response tab found in the CodeIgniter was this (this might be because of the csrf is not included in the post data):

An Error Was Encountered
The action you have requested is not allowed.

and for the php will just use this code (still not sure how will I handle it in php):

$_FILES['file']

I don't know how to upload an image using an uploader (that has preview of the file) and with csrf in CodeIgniter.

The process is this, upon select of image, an ajax will upload it to the server (temporary folder), and will return a new filename (encryption enabled upon upload in php)

halfer
  • 19,824
  • 17
  • 99
  • 186
Bry
  • 628
  • 1
  • 6
  • 17
  • I think you need to send 'CSRF' token by attaching it with the data in 'file' variable. Please find its structure and try by appending 'csrf' with it – Arun Apr 04 '16 at 11:08
  • assumming the csrf_val in the js has the 'CSRF' token. @arun – Bry Apr 04 '16 at 11:18
  • What I found on the net is either csrf only or image only in ajax. – Bry Apr 04 '16 at 11:22
  • It looks like you can submit a form with a file and other fields (including the hidden csrf token) using `enctype= multipart/form-data`. See [this answer](http://stackoverflow.com/a/20863123/3585500) as one example. – ourmandave Apr 04 '16 at 12:05
  • @ourmandave great thanks will check on that link. – Bry Apr 04 '16 at 12:14
  • I receive this error: " formData is not a constructor var posts = new formData( '#' + fid );" – Bry Apr 04 '16 at 12:17
  • Is it an IE issue? IE<10 doesn't like formData. There's a [jQuery plugin for that](http://stackoverflow.com/a/34917038/3585500). – ourmandave Apr 04 '16 at 12:21
  • I don't think its in IE issue, I try to adjust the codes and now my problem with regards to your suggestion and still MY_FAVICON is still not part of the serialization. @ourmandave – Bry Apr 04 '16 at 12:41

0 Answers0