2017-07-27 112 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

剛剛選中,它被設置爲發佈。 –