core security update
This commit is contained in:
@@ -632,7 +632,7 @@ function file_field_widget_process($element, &$form_state, $form) {
|
||||
$element['#theme'] = 'file_widget';
|
||||
|
||||
// Add the display field if enabled.
|
||||
if (!empty($field['settings']['display_field']) && $item['fid']) {
|
||||
if (!empty($field['settings']['display_field'])) {
|
||||
$element['display'] = array(
|
||||
'#type' => empty($item['fid']) ? 'hidden' : 'checkbox',
|
||||
'#title' => t('Include file in display'),
|
||||
|
||||
@@ -6,8 +6,8 @@ core = 7.x
|
||||
dependencies[] = field
|
||||
files[] = tests/file.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
; Information added by Drupal.org packaging script on 2016-10-05
|
||||
version = "7.51"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
datestamp = "1475694174"
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function file_theme() {
|
||||
'variables' => array('file' => NULL, 'icon_directory' => NULL),
|
||||
),
|
||||
'file_icon' => array(
|
||||
'variables' => array('file' => NULL, 'icon_directory' => NULL),
|
||||
'variables' => array('file' => NULL, 'icon_directory' => NULL, 'alt' => ''),
|
||||
),
|
||||
'file_managed_file' => array(
|
||||
'render element' => 'element',
|
||||
@@ -457,6 +457,17 @@ function file_managed_file_process($element, &$form_state, $form) {
|
||||
'#markup' => theme('file_link', array('file' => $element['#file'])) . ' ',
|
||||
'#weight' => -10,
|
||||
);
|
||||
// Anonymous users who have uploaded a temporary file need a
|
||||
// non-session-based token added so file_managed_file_value() can check
|
||||
// that they have permission to use this file on subsequent submissions of
|
||||
// the same form (for example, after an Ajax upload or form validation
|
||||
// error).
|
||||
if (!$GLOBALS['user']->uid && $element['#file']->status != FILE_STATUS_PERMANENT) {
|
||||
$element['fid_token'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => drupal_hmac_base64('file-' . $fid, drupal_get_private_key() . drupal_get_hash_salt()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the extension list to the page as JavaScript settings.
|
||||
@@ -529,14 +540,30 @@ function file_managed_file_value(&$element, $input = FALSE, $form_state = NULL)
|
||||
// publicly accessible, with no download restrictions; for security
|
||||
// reasons all other schemes must go through the file_download_access()
|
||||
// check.
|
||||
if (in_array(file_uri_scheme($file->uri), variable_get('file_public_schema', array('public'))) || file_download_access($file->uri)) {
|
||||
$fid = $file->fid;
|
||||
}
|
||||
// If the current user doesn't have access, don't let the file be
|
||||
// changed.
|
||||
else {
|
||||
if (!in_array(file_uri_scheme($file->uri), variable_get('file_public_schema', array('public'))) && !file_download_access($file->uri)) {
|
||||
$force_default = TRUE;
|
||||
}
|
||||
// Temporary files that belong to other users should never be allowed.
|
||||
elseif ($file->status != FILE_STATUS_PERMANENT) {
|
||||
if ($GLOBALS['user']->uid && $file->uid != $GLOBALS['user']->uid) {
|
||||
$force_default = TRUE;
|
||||
}
|
||||
// Since file ownership can't be determined for anonymous users, they
|
||||
// are not allowed to reuse temporary files at all. But they do need
|
||||
// to be able to reuse their own files from earlier submissions of
|
||||
// the same form, so to allow that, check for the token added by
|
||||
// file_managed_file_process().
|
||||
elseif (!$GLOBALS['user']->uid) {
|
||||
$token = drupal_array_get_nested_value($form_state['input'], array_merge($element['#parents'], array('fid_token')));
|
||||
if ($token !== drupal_hmac_base64('file-' . $file->fid, drupal_get_private_key() . drupal_get_hash_salt())) {
|
||||
$force_default = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If all checks pass, allow the file to be changed.
|
||||
if (!$force_default) {
|
||||
$fid = $file->fid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -749,7 +776,32 @@ function theme_file_link($variables) {
|
||||
$icon_directory = $variables['icon_directory'];
|
||||
|
||||
$url = file_create_url($file->uri);
|
||||
$icon = theme('file_icon', array('file' => $file, 'icon_directory' => $icon_directory));
|
||||
|
||||
// Human-readable names, for use as text-alternatives to icons.
|
||||
$mime_name = array(
|
||||
'application/msword' => t('Microsoft Office document icon'),
|
||||
'application/vnd.ms-excel' => t('Office spreadsheet icon'),
|
||||
'application/vnd.ms-powerpoint' => t('Office presentation icon'),
|
||||
'application/pdf' => t('PDF icon'),
|
||||
'video/quicktime' => t('Movie icon'),
|
||||
'audio/mpeg' => t('Audio icon'),
|
||||
'audio/wav' => t('Audio icon'),
|
||||
'image/jpeg' => t('Image icon'),
|
||||
'image/png' => t('Image icon'),
|
||||
'image/gif' => t('Image icon'),
|
||||
'application/zip' => t('Package icon'),
|
||||
'text/html' => t('HTML icon'),
|
||||
'text/plain' => t('Plain text icon'),
|
||||
'application/octet-stream' => t('Binary Data'),
|
||||
);
|
||||
|
||||
$mimetype = file_get_mimetype($file->uri);
|
||||
|
||||
$icon = theme('file_icon', array(
|
||||
'file' => $file,
|
||||
'icon_directory' => $icon_directory,
|
||||
'alt' => !empty($mime_name[$mimetype]) ? $mime_name[$mimetype] : t('File'),
|
||||
));
|
||||
|
||||
// Set options as per anchor format described at
|
||||
// http://microformats.org/wiki/file-format-examples
|
||||
@@ -779,16 +831,19 @@ function theme_file_link($variables) {
|
||||
* - file: A file object for which to make an icon.
|
||||
* - icon_directory: (optional) A path to a directory of icons to be used for
|
||||
* files. Defaults to the value of the "file_icon_directory" variable.
|
||||
* - alt: (optional) The alternative text to represent the icon in text-based
|
||||
* browsers. Defaults to an empty string.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_file_icon($variables) {
|
||||
$file = $variables['file'];
|
||||
$alt = $variables['alt'];
|
||||
$icon_directory = $variables['icon_directory'];
|
||||
|
||||
$mime = check_plain($file->filemime);
|
||||
$icon_url = file_icon_url($file, $icon_directory);
|
||||
return '<img class="file-icon" alt="" title="' . $mime . '" src="' . $icon_url . '" />';
|
||||
return '<img class="file-icon" alt="' . check_plain($alt) . '" title="' . $mime . '" src="' . $icon_url . '" />';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ class FileFieldTestCase extends DrupalWebTestCase {
|
||||
$modules[] = 'file';
|
||||
$modules[] = 'file_module_test';
|
||||
parent::setUp($modules);
|
||||
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access'));
|
||||
$this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access', 'administer fields'));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
}
|
||||
|
||||
@@ -218,6 +218,30 @@ class FileFieldTestCase extends DrupalWebTestCase {
|
||||
$message = isset($message) ? $message : format_string('File %file is permanent.', array('%file' => $file->uri));
|
||||
$this->assertTrue($file->status == FILE_STATUS_PERMANENT, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary file, for a specific user.
|
||||
*
|
||||
* @param string $data
|
||||
* A string containing the contents of the file.
|
||||
* @param int $uid
|
||||
* The user ID of the file owner.
|
||||
*
|
||||
* @return object
|
||||
* A file object, or FALSE on error.
|
||||
*/
|
||||
function createTemporaryFile($data, $uid = NULL) {
|
||||
$file = file_save_data($data, NULL, NULL);
|
||||
|
||||
if ($file) {
|
||||
$file->uid = isset($uid) ? $uid : $this->admin_user->uid;
|
||||
// Change the file status to be temporary.
|
||||
$file->status = NULL;
|
||||
return file_save($file);
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,6 +401,18 @@ class FileManagedFileElementTestCase extends FileFieldTestCase {
|
||||
$this->drupalPost($path, array(), t('Save'));
|
||||
$this->assertRaw(t('The file id is %fid.', array('%fid' => 0)), 'Submitted without a file.');
|
||||
|
||||
// Submit with a file, but with an invalid form token. Ensure the file
|
||||
// was not saved.
|
||||
$last_fid_prior = $this->getLastFileId();
|
||||
$edit = array(
|
||||
'files[' . $input_base_name . ']' => drupal_realpath($test_file->uri),
|
||||
'form_token' => 'invalid token',
|
||||
);
|
||||
$this->drupalPost($path, $edit, t('Save'));
|
||||
$this->assertText('The form has become outdated. Copy any unsaved work in the form below');
|
||||
$last_fid = $this->getLastFileId();
|
||||
$this->assertEqual($last_fid_prior, $last_fid, 'File was not saved when uploaded with an invalid form token.');
|
||||
|
||||
// Submit a new file, without using the Upload button.
|
||||
$last_fid_prior = $this->getLastFileId();
|
||||
$edit = array('files[' . $input_base_name . ']' => drupal_realpath($test_file->uri));
|
||||
@@ -514,6 +550,120 @@ class FileFieldWidgetTestCase extends FileFieldTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exploiting the temporary file removal of another user using fid.
|
||||
*/
|
||||
function testTemporaryFileRemovalExploit() {
|
||||
// Create a victim user.
|
||||
$victim_user = $this->drupalCreateUser();
|
||||
|
||||
// Create an attacker user.
|
||||
$attacker_user = $this->drupalCreateUser(array(
|
||||
'access content',
|
||||
'create page content',
|
||||
'edit any page content',
|
||||
));
|
||||
|
||||
// Log in as the attacker user.
|
||||
$this->drupalLogin($attacker_user);
|
||||
|
||||
// Perform tests using the newly created users.
|
||||
$this->doTestTemporaryFileRemovalExploit($victim_user->uid, $attacker_user->uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exploiting the temporary file removal for anonymous users using fid.
|
||||
*/
|
||||
public function testTemporaryFileRemovalExploitAnonymous() {
|
||||
// Set up an anonymous victim user.
|
||||
$victim_uid = 0;
|
||||
|
||||
// Set up an anonymous attacker user.
|
||||
$attacker_uid = 0;
|
||||
|
||||
// Set up permissions for anonymous attacker user.
|
||||
user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
|
||||
'access content' => TRUE,
|
||||
'create page content' => TRUE,
|
||||
'edit any page content' => TRUE,
|
||||
));
|
||||
|
||||
// In order to simulate being the anonymous attacker user, we need to log
|
||||
// out here since setUp() has logged in the admin.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Perform tests using the newly set up users.
|
||||
$this->doTestTemporaryFileRemovalExploit($victim_uid, $attacker_uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for testing exploiting the temporary file removal using fid.
|
||||
*
|
||||
* @param int $victim_uid
|
||||
* The victim user ID.
|
||||
* @param int $attacker_uid
|
||||
* The attacker user ID.
|
||||
*/
|
||||
protected function doTestTemporaryFileRemovalExploit($victim_uid, $attacker_uid) {
|
||||
// Use 'page' instead of 'article', so that the 'article' image field does
|
||||
// not conflict with this test. If in the future the 'page' type gets its
|
||||
// own default file or image field, this test can be made more robust by
|
||||
// using a custom node type.
|
||||
$type_name = 'page';
|
||||
$field_name = 'test_file_field';
|
||||
$this->createFileField($field_name, $type_name);
|
||||
|
||||
$test_file = $this->getTestFile('text');
|
||||
foreach (array('nojs', 'js') as $type) {
|
||||
// Create a temporary file owned by the anonymous victim user. This will be
|
||||
// as if they had uploaded the file, but not saved the node they were
|
||||
// editing or creating.
|
||||
$victim_tmp_file = $this->createTemporaryFile('some text', $victim_uid);
|
||||
$victim_tmp_file = file_load($victim_tmp_file->fid);
|
||||
$this->assertTrue($victim_tmp_file->status != FILE_STATUS_PERMANENT, 'New file saved to disk is temporary.');
|
||||
$this->assertFalse(empty($victim_tmp_file->fid), 'New file has a fid');
|
||||
$this->assertEqual($victim_uid, $victim_tmp_file->uid, 'New file belongs to the victim user');
|
||||
|
||||
// Have attacker create a new node with a different uploaded file and
|
||||
// ensure it got uploaded successfully.
|
||||
// @todo Can we test AJAX? See https://www.drupal.org/node/2538260
|
||||
$edit = array(
|
||||
'title' => $type . '-title',
|
||||
);
|
||||
|
||||
// Attach a file to a node.
|
||||
$langcode = LANGUAGE_NONE;
|
||||
$edit['files[' . $field_name . '_' . $langcode . '_0]'] = drupal_realpath($test_file->uri);
|
||||
$this->drupalPost("node/add/$type_name", $edit, 'Save');
|
||||
$node = $this->drupalGetNodeByTitle($edit['title']);
|
||||
$node_file = file_load($node->{$field_name}[$langcode][0]['fid']);
|
||||
$this->assertFileExists($node_file, 'New file saved to disk on node creation.');
|
||||
$this->assertEqual($attacker_uid, $node_file->uid, 'New file belongs to the attacker.');
|
||||
|
||||
// Ensure the file can be downloaded.
|
||||
$this->drupalGet(file_create_url($node_file->uri));
|
||||
$this->assertResponse(200, 'Confirmed that the generated URL is correct by downloading the shipped file.');
|
||||
|
||||
// "Click" the remove button (emulating either a nojs or js submission).
|
||||
// In this POST request, the attacker "guesses" the fid of the victim's
|
||||
// temporary file and uses that to remove this file.
|
||||
$this->drupalGet('node/' . $node->nid . '/edit');
|
||||
switch ($type) {
|
||||
case 'nojs':
|
||||
$this->drupalPost(NULL, array("{$field_name}[$langcode][0][fid]" => (string) $victim_tmp_file->fid), 'Remove');
|
||||
break;
|
||||
case 'js':
|
||||
$button = $this->xpath('//input[@type="submit" and @value="Remove"]');
|
||||
$this->drupalPostAJAX(NULL, array("{$field_name}[$langcode][0][fid]" => (string) $victim_tmp_file->fid), array((string) $button[0]['name'] => (string) $button[0]['value']));
|
||||
break;
|
||||
}
|
||||
|
||||
// The victim's temporary file should not be removed by the attacker's
|
||||
// POST request.
|
||||
$this->assertFileExists($victim_tmp_file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests upload and remove buttons for multiple multi-valued File fields.
|
||||
*/
|
||||
@@ -939,6 +1089,34 @@ class FileFieldDisplayTestCase extends FileFieldTestCase {
|
||||
$this->assertRaw($field_name . '[' . LANGUAGE_NONE . '][0][display]', 'First file appears as expected.');
|
||||
$this->assertRaw($field_name . '[' . LANGUAGE_NONE . '][1][display]', 'Second file appears as expected.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests default display of File Field.
|
||||
*/
|
||||
function testDefaultFileFieldDisplay() {
|
||||
$field_name = strtolower($this->randomName());
|
||||
$type_name = 'article';
|
||||
$field_settings = array(
|
||||
'display_field' => '1',
|
||||
'display_default' => '0',
|
||||
);
|
||||
$instance_settings = array(
|
||||
'description_field' => '1',
|
||||
);
|
||||
$widget_settings = array();
|
||||
$this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings);
|
||||
$field = field_info_field($field_name);
|
||||
$instance = field_info_instance('node', $field_name, $type_name);
|
||||
|
||||
$test_file = $this->getTestFile('text');
|
||||
|
||||
// Create a new node with the uploaded file.
|
||||
$nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
|
||||
|
||||
$this->drupalGet('node/' . $nid . '/edit');
|
||||
$this->assertFieldByXPath('//input[@type="checkbox" and @name="' . $field_name . '[und][0][display]"]', NULL, 'Default file display checkbox field exists.');
|
||||
$this->assertFieldByXPath('//input[@type="checkbox" and @name="' . $field_name . '[und][0][display]" and not(@checked)]', NULL, 'Default file display is off.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1325,3 +1503,178 @@ class FilePrivateTestCase extends FileFieldTestCase {
|
||||
$this->assertResponse(403, 'Confirmed that access is denied for the file without view field access permission after attempting to attach it to a new node.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that file field submissions work correctly for anonymous visitors.
|
||||
*/
|
||||
class FileFieldAnonymousSubmission extends FileFieldTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'File form anonymous submission',
|
||||
'description' => 'Test anonymous form submission.',
|
||||
'group' => 'File',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Allow node submissions by anonymous users.
|
||||
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
|
||||
'create article content',
|
||||
'access content',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the basic node submission for an anonymous visitor.
|
||||
*/
|
||||
function testAnonymousNode() {
|
||||
$bundle_label = 'Article';
|
||||
$node_title = 'Test page';
|
||||
|
||||
// Load the node form.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertResponse(200, 'Loaded the article node form.');
|
||||
$this->assertText(strip_tags(t('Create @name', array('@name' => $bundle_label))));
|
||||
|
||||
$edit = array(
|
||||
'title' => $node_title,
|
||||
'body[und][0][value]' => 'Test article',
|
||||
'body[und][0][format]' => 'filtered_html',
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$t_args = array('@type' => $bundle_label, '%title' => $node_title);
|
||||
$this->assertText(strip_tags(t('@type %title has been created.', $t_args)), 'The node was created.');
|
||||
$matches = array();
|
||||
if (preg_match('@node/(\d+)$@', $this->getUrl(), $matches)) {
|
||||
$nid = end($matches);
|
||||
$this->assertNotEqual($nid, 0, 'The node ID was extracted from the URL.');
|
||||
$node = node_load($nid);
|
||||
$this->assertNotEqual($node, NULL, 'The node was loaded successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests file submission for an anonymous visitor.
|
||||
*/
|
||||
function testAnonymousNodeWithFile() {
|
||||
$bundle_label = 'Article';
|
||||
$node_title = 'Test page';
|
||||
|
||||
// Load the node form.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertResponse(200, 'Loaded the article node form.');
|
||||
$this->assertText(strip_tags(t('Create @name', array('@name' => $bundle_label))));
|
||||
|
||||
// Generate an image file.
|
||||
$image = $this->getTestImage();
|
||||
|
||||
// Submit the form.
|
||||
$edit = array(
|
||||
'title' => $node_title,
|
||||
'body[und][0][value]' => 'Test article',
|
||||
'body[und][0][format]' => 'filtered_html',
|
||||
'files[field_image_und_0]' => drupal_realpath($image->uri),
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$t_args = array('@type' => $bundle_label, '%title' => $node_title);
|
||||
$this->assertText(strip_tags(t('@type %title has been created.', $t_args)), 'The node was created.');
|
||||
$matches = array();
|
||||
if (preg_match('@node/(\d+)$@', $this->getUrl(), $matches)) {
|
||||
$nid = end($matches);
|
||||
$this->assertNotEqual($nid, 0, 'The node ID was extracted from the URL.');
|
||||
$node = node_load($nid);
|
||||
$this->assertNotEqual($node, NULL, 'The node was loaded successfully.');
|
||||
$this->assertEqual($node->field_image[LANGUAGE_NONE][0]['filename'], $image->filename, 'The image was uploaded successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests file submission for an anonymous visitor with a missing node title.
|
||||
*/
|
||||
function testAnonymousNodeWithFileWithoutTitle() {
|
||||
$this->drupalLogout();
|
||||
$this->_testNodeWithFileWithoutTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests file submission for an authenticated user with a missing node title.
|
||||
*/
|
||||
function testAuthenticatedNodeWithFileWithoutTitle() {
|
||||
$admin_user = $this->drupalCreateUser(array(
|
||||
'bypass node access',
|
||||
'access content overview',
|
||||
'administer nodes',
|
||||
));
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->_testNodeWithFileWithoutTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to test file submissions with missing node titles.
|
||||
*/
|
||||
protected function _testNodeWithFileWithoutTitle() {
|
||||
$bundle_label = 'Article';
|
||||
$node_title = 'Test page';
|
||||
|
||||
// Load the node form.
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertResponse(200, 'Loaded the article node form.');
|
||||
$this->assertText(strip_tags(t('Create @name', array('@name' => $bundle_label))));
|
||||
|
||||
// Generate an image file.
|
||||
$image = $this->getTestImage();
|
||||
|
||||
// Submit the form but exclude the title field.
|
||||
$edit = array(
|
||||
'body[und][0][value]' => 'Test article',
|
||||
'body[und][0][format]' => 'filtered_html',
|
||||
'files[field_image_und_0]' => drupal_realpath($image->uri),
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
$this->assertResponse(200);
|
||||
$t_args = array('@type' => $bundle_label, '%title' => $node_title);
|
||||
$this->assertNoText(strip_tags(t('@type %title has been created.', $t_args)), 'The node was created.');
|
||||
$this->assertText(t('!name field is required.', array('!name' => t('Title'))));
|
||||
|
||||
// Submit the form again but this time with the missing title field. This
|
||||
// should still work.
|
||||
$edit = array(
|
||||
'title' => $node_title,
|
||||
);
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
|
||||
// Confirm the final submission actually worked.
|
||||
$t_args = array('@type' => $bundle_label, '%title' => $node_title);
|
||||
$this->assertText(strip_tags(t('@type %title has been created.', $t_args)), 'The node was created.');
|
||||
$matches = array();
|
||||
if (preg_match('@node/(\d+)$@', $this->getUrl(), $matches)) {
|
||||
$nid = end($matches);
|
||||
$this->assertNotEqual($nid, 0, 'The node ID was extracted from the URL.');
|
||||
$node = node_load($nid);
|
||||
$this->assertNotEqual($node, NULL, 'The node was loaded successfully.');
|
||||
$this->assertEqual($node->field_image[LANGUAGE_NONE][0]['filename'], $image->filename, 'The image was uploaded successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a test image.
|
||||
*
|
||||
* @return stdClass
|
||||
* A file object.
|
||||
*/
|
||||
function getTestImage() {
|
||||
// Get a file to upload.
|
||||
$file = current($this->drupalGetTestFiles('image'));
|
||||
|
||||
// Add a filesize property to files as would be read by file_load().
|
||||
$file->filesize = filesize($file->uri);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2015-04-02
|
||||
version = "7.36"
|
||||
; Information added by Drupal.org packaging script on 2016-10-05
|
||||
version = "7.51"
|
||||
project = "drupal"
|
||||
datestamp = "1427943826"
|
||||
datestamp = "1475694174"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user