2017-07-27 108 views
0

我正在构建一个Laravel 5.4应用程序,让您将图像上传到每个注册条目。我使用的干预图像包,但意识到我需要一种方式来启用图像裁剪和旋转(iphone图像旋转时,上传由于某种原因),所以我决定使用jQuery插件Slim Cropper。我已将必要的文件添加到我的代码中,但无法成功上传图像。laravel 5.4中的TokenMismatchException与图像上传

Slim Cropper提供了两种上传图片的方法:通过一个常规的表单,在提交后给出"TokenMismatchException in VerifyCsrfToken.php (line 68)",以及一个简单显示“无法上传”消息的ajax表单。我已经尝试了两种不同的更改,但无法实现。我所有的类/控制器都会检查身份验证,并且我尝试以我能想到的方式发送csrf标记,并显示相同的错误。


UPDATE:按照注释中的建议,我已经<form>后移动CSRF令牌吧,我已经更新了输入文件名匹配那些从例子,试图通过中间件,并没有错误调试无论如何。 TokenMismatchException错误不再是一个问题,但一旦提交表格,我会得到Constant expression contains invalid operations in Slim.php (line 106)的错误public static function saveFile($data, $name, $path = public_path('/uploads/mascotas-img/'), $uid = true)。仍然没有解决这个问题。

下面的代码:

路线

Route::post('/mascotas/avatar', '[email protected]'); 

宠物控制器

use App\Slim; 
public function avatar(Request $request) 
{ 
    if ($request->avatar) 
    { 
     // Pass Slim's getImages the name of your file input, and since we only care about one image, postfix it with the first array key 
     $image = Slim::getImages('avatar')[0]; 
     $mascota_num = $image['meta']->petId; 

     // Grab the ouput data (data modified after Slim has done its thing) 
     if (isset($image['output']['data'])) 
     { 
      // Original file name 
      $name = $image['output']['name']; 
      //$name = $request->input('mascota_num'); 

      // Base64 of the image 
      $data = $image['output']['data']; 

      // Server path 
      $path = public_path('/uploads/mascotas-img/'); 

      // Save the file to the server 
      $file = Slim::saveFile($data, $name, $path); 

      // Get the absolute web path to the image 
      $imagePath = public_path('/uploads/mascotas-img/' . $file['name']); 

      DB::table('mascotas') 
       ->where('num',$mascota_num) 
       ->update(['foto' => $imagePath]); 

      //$mascota->foto = $imagePath; 
      //$mascota->save(); 
     } 
    } 

    return redirect()->back()->with('success', "User's profile picture has been updated!"); 
} 

修身类

namespace App; 

abstract class SlimStatus { 
    const Failure = 'failure'; 
    const Success = 'success'; 
} 

class Slim { 

    public static function getImages($inputName = 'slim') { 

     $values = Slim::getPostData($inputName); 

     // test for errors 
     if ($values === false) { 
      return false; 
     } 

     // determine if contains multiple input values, if is singular, put in array 
     $data = array(); 
     if (!is_array($values)) { 
      $values = array($values); 
     } 

     // handle all posted fields 
     foreach ($values as $value) { 
      $inputValue = Slim::parseInput($value); 
      if ($inputValue) { 
       array_push($data, $inputValue); 
      } 
     } 

     // return the data collected from the fields 
     return $data; 

    } 

    // $value should be in JSON format 
    private static function parseInput($value) { 

     // if no json received, exit, don't handle empty input values. 
     if (empty($value)) {return null;} 

     // The data is posted as a JSON String so to be used it needs to be deserialized first 
     $data = json_decode($value); 

     // shortcut 
     $input = null; 
     $actions = null; 
     $output = null; 
     $meta = null; 

     if (isset ($data->input)) { 
      $inputData = isset($data->input->image) ? Slim::getBase64Data($data->input->image) : null; 
      $input = array(
       'data' => $inputData, 
       'name' => $data->input->name, 
       'type' => $data->input->type, 
       'size' => $data->input->size, 
       'width' => $data->input->width, 
       'height' => $data->input->height, 
      ); 
     } 

     if (isset($data->output)) { 
      $outputData = isset($data->output->image) ? Slim::getBase64Data($data->output->image) : null; 
      $output = array(
       'data' => $outputData, 
       'width' => $data->output->width, 
       'height' => $data->output->height 
      ); 
     } 

     if (isset($data->actions)) { 
      $actions = array(
       'crop' => $data->actions->crop ? array(
        'x' => $data->actions->crop->x, 
        'y' => $data->actions->crop->y, 
        'width' => $data->actions->crop->width, 
        'height' => $data->actions->crop->height, 
        'type' => $data->actions->crop->type 
       ) : null, 
       'size' => $data->actions->size ? array(
        'width' => $data->actions->size->width, 
        'height' => $data->actions->size->height 
       ) : null 
      ); 
     } 

     if (isset($data->meta)) { 
      $meta = $data->meta; 
     } 

     // We've sanitized the base64data and will now return the clean file object 
     return array(
      'input' => $input, 
      'output' => $output, 
      'actions' => $actions, 
      'meta' => $meta 
     ); 
    } 

    // $path should have trailing slash 
    public static function saveFile($data, $name, $path = public_path('/uploads/mascotas-img/'), $uid = true) { 

     // Add trailing slash if omitted 
     if (substr($path, -1) !== '/') { 
      $path .= '/'; 
     } 

     // Test if directory already exists 
     if(!is_dir($path)){ 
      mkdir($path, 0755); 
     } 

     // Let's put a unique id in front of the filename so we don't accidentally overwrite older files 
     if ($uid) { 
      $name = uniqid() . '_' . $name; 
     } 
     $path = $path . $name; 

     // store the file 
     Slim::save($data, $path); 

     // return the files new name and location 
     return array(
      'name' => $name, 
      'path' => $path 
     ); 
    } 

    public static function outputJSON($status, $fileName = null, $filePath = null) { 

     header('Content-Type: application/json'); 

     if ($status !== SlimStatus::Success) { 
      echo json_encode(array('status' => $status)); 
      return; 
     } 

     echo json_encode(
      array(
       'status' => $status, 
       'name' => $fileName, 
       'path' => $filePath 
      ) 
     ); 
    } 

    /** 
    * Gets the posted data from the POST or FILES object. If was using Slim to upload it will be in POST (as posted with hidden field) if not enhanced with Slim it'll be in FILES. 
    * @param $inputName 
    * @return array|bool 
    */ 
    private static function getPostData($inputName) { 

     $values = array(); 

     if (isset($_POST[$inputName])) { 
      $values = $_POST[$inputName]; 
     } 
     else if (isset($_FILES[$inputName])) { 
      // Slim was not used to upload this file 
      return false; 
     } 

     return $values; 
    } 

    /** 
    * Saves the data to a given location 
    * @param $data 
    * @param $path 
    */ 
    private static function save($data, $path) { 
     file_put_contents($path, $data); 
    } 

    /** 
    * Strips the "data:image..." part of the base64 data string so PHP can save the string as a file 
    * @param $data 
    * @return string 
    */ 
    private static function getBase64Data($data) { 
     return base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data)); 
    } 

} 

图片提交表格(tokenmismatch误差)

<form action="{{ url('mascotas/avatar') }}" method="post" enctype="multipart/form-data"> 
    <div class="modal-body"> 
     <div class="slim" data-label="Agregar imagen aquí" data-size="400, 400" data-ratio="1:1" data-meta-pet-id="{{ $mascota->num }}"> 
      @if ($mascota->foto) 
       <img src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}" /> 
      @endif 
      <input type="file" name="avatar" required /> 
      {{ csrf_field() }} 
     </div> 
    </div> 
    <div class="modal-footer"> 
     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> 
     <button type="submit" class="btn btn-red">Cambiar Foto</button> 
    </div> 
</form> 

替代提交表格(出错消息)

<div class="modal-body"> 
    <div class="slim" data-label="Agregar imagen aquí" data-size="400, 400" data-ratio="1:1" data-service="{{ url('mascotas/avatar') }}" data-meta-pet-id="{{ $mascota->num }}"> 
     @if ($mascota->foto) 
      <img src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}" /> 
     @endif 
     <input type="file" name="avatar" /> 
    </div> 
</div> 
<div class="modal-footer"> 
    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> 
    <button type="submit" class="btn btn-red">Cambiar Foto</button> 
</div> 

苗条图像裁剪网站与实例http://slimimagecropper.com/


我的原始上传表单通过laravel图像插入,这在上传时没有问题,但非常希望用上述之一替换。

<form enctype="multipart/form-data" action="{{ url('mascotas/foto') }}" method="POST"> 
    <div class="modal-body"> 
     <img class="mascota-avatar" src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}"> 
     <div class="clearfix"></div> 
     <input type="file" name="foto"> 
     <input type="hidden" name="_token" value="{{ csrf_token() }}"> 
     <input type="hidden" name="mascota_num" value="{{ $mascota->num }}"> 
    </div> 
    <div class="modal-footer"> 
     <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> 
     <button type="submit" class="btn btn-red">Cambiar Foto</button> 
    </div> 
</form> 

感谢您的帮助!

+0

_token隐藏输入不在您的其他表单中,它用于laravel中的CSRF检查,https://laravel.com/docs/5.4/csrf,您是否尝试过在您的Slim表单中包含隐藏输入? – N3SS4H

+0

是的,我试过了,它给了我同样的错误,这就是为什么我无法弄清楚为什么它不起作用。 –

+0

尝试在中间件上进行调试,方法是允许url通过csrf检查并将其添加到位于$ except数组中的verifyCsrfToken中间件,如下所示:protected $ except = [ '/ pass/this/url' ];并看看是否有用,然后尝试找到什么导致它,如果它通过 – Birdy

回答

1

您应该在每个表单上包含{{ csrf_field() }},对于Ajax表单,您可以将标记作为标题发送。

+0

已尝试以我能想到的方式发送令牌,但我仍然得到同样的错误,不知道为什么。 –

+0

在控制台上检查您使用的插件(苗条裁剪器)发送的请求类型,检查它是否确实是“发布” –

+0

刚刚选中,它被设置为发布。 –