Dear Support,

I have faced an issue that if I upload the image through REST with a file tree (example: file[filepath] = public://post/test1/test2/test3/img5.jpg), I can upload it successfully, but the image style can't generate the image for node, hard to explain by words, please have a look the attached screen shot.

If I upload the image at root folder (example file[filepath] = public://img5.jpg), everything is normal, image style can generate, node also can show the image.

Thanks for reviewing the bug.

01


02


03


04


05

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

igetquestion created an issue. See original summary.

igetquestion’s picture

igetquestion’s picture

Issue summary: View changes
facuchaer’s picture

Had the same exact issue, ussing "target_uri"... i need to save the file in a folder, already spend 4 hours on this.. tried to find an "official" documentation, but took me to pages and pages and pages of nothing. do you manage to get this working?

kylebrowning’s picture

You can check the tests. We upload via that and attached to a node.

igetquestion’s picture

Dear kylebrowning,

Thanks for the reply, thanks for the module, I have been looking for someone to help look into the image path issue.
May I have more detail on how to REST upload an image with file tree? I have been stuck on this issue.

BTW, what do your mean "You can check the tests. We upload via that and attached to a node." ?

Thanks.

facuchaer’s picture

FileSize
81.62 KB
17.59 KB

@kylebrowning, just checked the test page

  /**
   * Test create method.
   */
  public function testResourceFileCreate() {
    // Create file argument with data.
    $filepath = file_default_scheme() . '://' . rand() . '/' . rand() . '/' . $this->testfile->filename;
    $file = array(
      'filesize' => filesize($this->testfile->uri),
      'filename' => $this->testfile->filename,
      'filepath' => $filepath,
      'file' => base64_encode(file_get_contents($this->testfile->uri)),
      'uid' => $this->privileged_user->uid,
    );

    // Create file with call.
    $result = $this->servicesPost($this->endpoint->path . '/file', $file);
    $this->assertEqual($result['code'], 200, 'File created.', 'FileResource: Create');

    // Load file and assert that it exists.
    $file_load = file_load($result['body']['fid']);
    $this->assertTrue(is_file($file_load->uri), 'New file saved to disk.', 'FileResource: Create');
    $this->assertEqual($file_load->uri, $filepath,
      'The path of newly created file placed into directory with random name.', 'FileResource: Create');
  }

there's nothing "special" about it. but i've tried to do it just like that and had the same results as @igetquestion

asd

here the response:

asd

my code:

      ref.sendImage = function (img){
        var deferred = $q.defer();
        var url = ref.endpoint + '/image.json';

        var data = {
          'filepath': img.filepath,
          'filename' : img.filename,
          'file' : img.file,
          'size' : img.size,
          'uid' : 4
        };

        var req = {
          method: 'POST',
          url: url,
          headers: {
            'Content-Type': 'application/json',
          },
          data: data
        };

        $http(req).then(function (resp) {
          if (resp.status === 200) {
            deferred.resolve(resp.data);
          } else {
            deferred.reject(resp);
          }
        }, function (error) {
          deferred.reject(error);
        });
        return deferred.promise;
      };

p/d: im using "image" as alias for file resource.

facuchaer’s picture

so.. news... i've been checking services code, and here is the issue:

on file_resource.inc

function _file_resource_create($file) {
  // Adds backwards compatability with regression fixed in #1083242
  // $file['file'] can be base64 encoded file so we check whether it is
  // file array or file data.
  $file = _services_arg_value($file, 'file');

  // If the file data or filename is empty then bail.
  if (!isset($file['file']) || empty($file['filename'])) {
    return services_error(t("Missing data the file upload can not be completed"), 500);
  }

  // Sanitize the file extension, name, path and scheme provided by the user.
  $destination = empty($file['filepath'])
    ? file_default_scheme() . '://' . _services_file_check_destination($file['filename'])
    : _services_file_check_destination_uri($file['filepath']);

  $dir = drupal_dirname($destination);
  // Build the destination folder tree if it doesn't already exists.
  if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY)) {
    return services_error(t("Could not create destination directory for file."), 500);
  }

  // Write the file
  if (!$file_saved = file_save_data(base64_decode($file['file']), $destination)) {
    return services_error(t("Could not write file to destination"), 500);
  }

  if (isset($file['status']) && $file['status'] == 0) {
    // Save as temporary file.
    $file_saved->status = 0;
    file_save($file_saved);
  }
  else {
    // Required to be able to reference this file.
    file_usage_add($file_saved, 'services', 'files', $file_saved->fid);
  }

  return array(
    'fid' => $file_saved->fid,
    'uri' => services_resource_uri(array('file', $file_saved->fid)),
  );
}

everything is ok unitl the "return array" part, is calling to serices_resource_uri with string file and fid as parameters

/**
 * Formats a resource uri using the formatter registered through
 * services_set_server_info().
 *
 * @param array $path
 *  An array of strings containing the component parts of the path to the resource.
 * @return string
 *  Returns the formatted resource uri, or NULL if no formatter has been registered.
 */
function services_resource_uri($path) {
  $endpoint_name = services_get_server_info('endpoint');
  $endpoint = services_endpoint_load($endpoint_name);
  if (!empty($path[0]) && !empty($endpoint->resources[$path[0]]['alias'])) {
    $path[0] = $endpoint->resources[$path[0]]['alias'];
  }
  $formatter = services_get_server_info('resource_uri_formatter');
  if ($formatter) {
    return call_user_func($formatter, $path);
  }
  return NULL;
}

further debuggin on the services_resource_uri as states on the declaration takes "path" which is an array but it says containing the component parts of the path. and this is as far as i can get, since i don't know how services work but this where all gets the wrong way and returns wrong stuff.

but i can confirm if you change

  return array(
    'fid' => $file_saved->fid,
     'uri' => services_resource_uri(array('file', $file_saved->fid)),
);

to

  return array(
    'fid' => $file_saved->fid,
    'uri' => $file_saved->uri,
  );

everything works fine and also makes more sense (again i don't know about services internals, maybe im doing something extremly wrong).

kylebrowning’s picture

Well you're posting to `+ '/image.json';` Is that correct?

Cause in the test we are posting to `/file`

facuchaer’s picture

FileSize
85.18 KB
17.78 KB

mmmm.. don't get what you'r trying to point out with that. but changing to /file makes no difference.

asd

here the response:

asd

facuchaer’s picture

FileSize
18.71 KB

just checked with a co-worker, and it's ok.. the URI is not the content (file) url, it's the services endpoint url to obtain the file. my bad, all this time i was thinking that should retrieve the URI with "public//: etc etc). but calling to the reponse uri, gives u the real uri of the file. or full uri. here the request:

a

(with requested uri, you are saying the name as it's of the resource, note that if duplicated will give integrity costraint violation, use only filename with path).

gives as response:

{"fid":"599","uri":"http://localhost/knauf/v4_admin/adp/api/1.0/file/599"}

when calling to that uri (resource one):

....."uri":"public://typology/images/images.jpg"......... "uri_full":"http://localhost/knauf/v4_admin/sites/default/files/typology/images/images.jpg"........

EDIT:
@igetquestion, does this help with your issue? see this is not a bug, i think we miss understood how file upload works, and it's working as designed, maybe it's a feature request, but not a bug. let them know so the bug can be closed.

regards.

igetquestion’s picture

FileSize
55.9 KB
73.9 KB

Dear facuchaer,

Im using chrome postman to test, but I get this return:

..........
"uri": "public://rest_upload\\node\\img5.jpg",
..........
"uri_full": "http://localhost/d755dev/sites/default/files/rest_upload/node/img5.jpg",
"target_uri": "rest_upload\\node\\img5.jpg",
..........

restupload 01.JPG
upload ok. I use filename with path for "file[filename]".

restupload 02.JPG

The "uri" and "target_uri" contain double backslash which making the image style cant generate image for node.

Can help on this?

Im been stack few weeks on this issue...

Thanks and regards.

marcingy’s picture

Category: Bug report » Support request
facuchaer’s picture

@igetquestion have u tried without filepath? try only with filename (with path) im posting like that without problems. also try it and debug it on application... sometimes json responses cantain backslashes that are trimed when you decode them.

igetquestion’s picture

@facuchaer, Im tried but no luck, still the same issue getting double back slashes...

Can you help using windows chrome postman to test?

igetquestion’s picture

@facuchaer & @kylebrowning, I think im found out the issue in file_resource.inc at line 428:

"return implode(DIRECTORY_SEPARATOR, $directories);"

I changed to below line and solved my issue, but im still wish it can be review and officially updated for the future update.

"return implode('/', $directories);"

Im using WAMP in Windows system, "DIRECTORY_SEPARATOR" in windows system become double backslashes.

slhemanthkumar’s picture

FileSize
50.09 KB
45.78 KB

To get URI and Target URI same, we need to pass same value in the file path and file name. Please find the attached postman screenshots for more information. I'm using Drupal 7 and Servcies 3 module.

REST

POSTMAN

Regards
Hemanth