/** * {@inheritdoc} */ public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) { // If we're stubbing a file entity, return a uri of NULL so it will get // stubbed by the general process. if ($row->isStub()) { return NULL; } list($source, $destination) = $value; // Modify the destination filename if necessary. $replace = !empty($this->configuration['rename']) ? FILE_EXISTS_RENAME : FILE_EXISTS_REPLACE; $final_destination = file_destination($destination, $replace); // Try opening the file first, to avoid calling file_prepare_directory() // unnecessarily. We're suppressing fopen() errors because we want to try // to prepare the directory before we give up and fail. $destination_stream = @fopen($final_destination, 'w'); if (!$destination_stream) { // If fopen didn't work, make sure there's a writable directory in place. $dir = $this->fileSystem->dirname($final_destination); if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) { throw new MigrateException("Could not create or write to directory '{$dir}'"); } // Let's try that fopen again. $destination_stream = @fopen($final_destination, 'w'); if (!$destination_stream) { throw new MigrateException("Could not write to file '{$final_destination}'"); } } // Stream the request body directly to the final destination stream. $this->configuration['guzzle_options']['sink'] = $destination_stream; // Make the request. Guzzle throws an exception for anything other than 200. $this->httpClient->get($source, $this->configuration['guzzle_options']); return $final_destination; }
/** * Tests derivative creation with several source on a local writable stream. * * @dataProvider providerTestCustomStreamWrappers * * @param string $source_scheme * The source stream wrapper scheme. * @param string $expected_scheme * The derivative expected stream wrapper scheme. */ public function testCustomStreamWrappers($source_scheme, $expected_scheme) { $derivative_uri = $this->imageStyle->buildUri("{$source_scheme}://some/path/image.png"); $derivative_scheme = $this->fileSystem->uriScheme($derivative_uri); // Check that the derivative scheme is the expected scheme. $this->assertSame($expected_scheme, $derivative_scheme); // Check that the derivative URI is the expected one. $expected_uri = "{$expected_scheme}://styles/{$this->imageStyle->id()}/{$source_scheme}/some/path/image.png"; $this->assertSame($expected_uri, $derivative_uri); }
/** * Locates a library. * * @param \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $library * The library to locate. * * @see \Drupal\libraries\ExternalLibrary\Local\LocatorInterface::locate() */ public function locate(LocalLibraryInterface $library) { $path = $this->fileSystemHelper->realpath($this->getUri($library)); if ($path && is_dir($path) && is_readable($path)) { // Set a path relative to the app root. assert('strpos($path, $this->appRoot . "/") === 0', "Path: {$path}"); $path = str_replace($this->appRoot . '/', '', $path); assert('$path[0] !== "/"'); $library->setLocalPath($path); } else { $library->setUninstalled(); } }
/** * Submit handler to write an unmanaged file using plain PHP functions. * * The key functions used here are: * - file_unmanaged_save_data(), which takes a buffer and saves it to a named * file, but does not create any kind of tracking record in the database. * - file_create_url(), which converts a URI in the form public://junk.txt or * private://something/test.txt into a URL like * http://example.com/sites/default/files/junk.txt. * - drupal_tempnam() generates a temporary filename for use. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ public function handleUnmanagedPhp(array &$form, FormStateInterface $form_state) { $form_values = $form_state->getValues(); $data = $form_values['write_contents']; $destination = !empty($form_values['destination']) ? $form_values['destination'] : NULL; if (empty($destination)) { // If no destination has been provided, use a generated name. $destination = $this->fileSystem->tempnam('public://', 'file'); } // With all traditional PHP functions we can use the stream wrapper notation // for a file as well. $fp = fopen($destination, 'w'); // To demonstrate the fact that everything is based on streams, we'll do // multiple 5-character writes to put this to the file. We could easily // (and far more conveniently) write it in a single statement with // fwrite($fp, $data). $length = strlen($data); $write_size = 5; for ($i = 0; $i < $length; $i += $write_size) { $result = fwrite($fp, substr($data, $i, $write_size)); if ($result === FALSE) { drupal_set_message(t('Failed writing to the file %file', array('%file' => $destination)), 'error'); fclose($fp); return; } } $url = $this->getExternalUrl($destination); $this->setDefaultFile($destination); if ($url) { drupal_set_message($this->t('Saved file as %filename (accessible via <a href=":url">this URL</a>, uri=<span id="uri">@uri</span>)', array('%filename' => $destination, '@uri' => $destination, ':url' => $url->toString()))); } else { drupal_set_message($this->t('Saved file as %filename (not accessible externally)', array('%filename' => $destination, '@uri' => $destination))); } }
/** * {@inheritdoc} */ public function transformDimensions(array &$dimensions, $uri) { // Test to see if EXIF is supported by the image format. $mime_type = $this->mimeTypeGuesser->guess($uri); if (!in_array($mime_type, ['image/jpeg', 'image/tiff'])) { // Not an EXIF enabled image, return. return; } if ($dimensions['width'] && $dimensions['height'] && $this->configuration['scan_exif']) { // Both dimensions in input, and effect is configured to check the // the input file. Read EXIF data, and determine image orientation. if (($file_path = $this->fileSystem->realpath($uri)) && function_exists('exif_read_data')) { if ($exif_data = @exif_read_data($file_path)) { $orientation = isset($exif_data['Orientation']) ? $exif_data['Orientation'] : NULL; if (in_array($orientation, [5, 6, 7, 8])) { $tmp = $dimensions['width']; $dimensions['width'] = $dimensions['height']; $dimensions['height'] = $tmp; } return; } } } // Either no full dimensions in input, or effect is configured to skip // checking the input file, or EXIF extension is missing. Set both // dimensions to NULL. $dimensions['width'] = $dimensions['height'] = NULL; }
/** * Test successful moves. */ public function testSuccessfulMoves() { $file_1 = $this->createUri(NULL, NULL, 'temporary'); $file_1_absolute = $this->fileSystem->realpath($file_1); $file_2 = $this->createUri(NULL, NULL, 'temporary'); $file_2_absolute = $this->fileSystem->realpath($file_2); $local_file = $this->createUri(NULL, NULL, 'public'); $data_sets = [[$local_file, 'public://file1.jpg'], [$file_1_absolute, 'temporary://test.jpg'], [$file_2_absolute, 'temporary://core/modules/simpletest/files/test.jpg']]; foreach ($data_sets as $data) { list($source_path, $destination_path) = $data; $actual_destination = $this->doImport($source_path, $destination_path, ['move' => TRUE]); $message = sprintf('File %s exists', $destination_path); $this->assertFileExists($destination_path, $message); $message = sprintf('File %s does not exist', $source_path); $this->assertFileNotExists($source_path, $message); $this->assertSame($actual_destination, $destination_path, 'The importer returned the moved filename.'); } }
/** * Determines if the given URI or path is considered local. * * A URI or path is considered local if it either has no scheme component, * or the scheme is implemented by a stream wrapper which extends * \Drupal\Core\StreamWrapper\LocalStream. * * @param string $uri * The URI or path to test. * * @return bool */ protected function isLocalUri($uri) { $scheme = $this->fileSystem->uriScheme($uri); // The vfs scheme is vfsStream, which is used in testing. vfsStream is a // simulated file system that exists only in memory, but should be treated // as a local resource. if ($scheme == 'vfs') { $scheme = FALSE; } return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream; }
/** * {@inheritdoc} */ public function denormalize($data, $class, $format = NULL, array $context = array()) { // File content can be passed base64 encoded in a special "data" property. // That property is not a field, so we remove it before denormalizing the // rest of the file entity. $file_data = $data['data'][0]['value']; unset($data['data']); $entity = parent::denormalize($data, $class, $format, $context); // Decode and save to file if it's a new file. if (!isset($context['request_method']) || $context['request_method'] != 'patch') { $file_contents = base64_decode($file_data); $dirname = $this->fileSystem->dirname($entity->getFileUri()); file_prepare_directory($dirname, FILE_CREATE_DIRECTORY); if ($uri = file_unmanaged_save_data($file_contents, file_build_uri(drupal_basename($entity->getFilename())))) { $entity->setFileUri($uri); } else { throw new RuntimeException('failed to write ' . $entity->getFilename()); } } return $entity; }
/** * Writes a file to the file system, creating its directory as needed. * * @param string $directory * The extension's directory. * @param array $file * Array with the following keys: * - 'filename': the name of the file. * - 'subdirectory': any subdirectory of the file within the extension * directory. * - 'string': the contents of the file. * * @throws Exception */ protected function generateFile($directory, array $file) { if (!empty($file['subdirectory'])) { $directory .= '/' . $file['subdirectory']; } $directory = $this->root . '/' . $directory; if (!is_dir($directory)) { if ($this->fileSystem->mkdir($directory, NULL, TRUE) === FALSE) { throw new \Exception($this->t('Failed to create directory @directory.', ['@directory' => $directory])); } } if (file_put_contents($directory . '/' . $file['filename'], $file['string']) === FALSE) { throw new \Exception($this->t('Failed to write file @filename.', ['@filename' => $file['filename']])); } }
/** * Locate all images in a piece of text that need replacing. * * An array of settings that will be used to identify which images need * updating. Includes the following: * * - image_locations: An array of acceptable image locations. * of the following values: "remote". Remote image will be downloaded and * saved locally. This procedure is intensive as the images need to * be retrieved to have their dimensions checked. * * @param string $text * The text to be updated with the new img src tags. * * @return array $images * An list of images. */ private function getImages($text) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); /** @var \DOMNode $node */ foreach ($xpath->query('//img') as $node) { $file = $this->entityRepository->loadEntityByUuid('file', $node->getAttribute('data-entity-uuid')); // If the image hasn't an uuid then don't try to resize it. if (is_null($file)) { continue; } $image = $this->imageFactory->get($node->getAttribute('src')); // Checking if the image needs to be resized. if ($image->getWidth() == $node->getAttribute('width') && $image->getHeight() == $node->getAttribute('height')) { continue; } $target = file_uri_target($file->getFileUri()); $dirname = dirname($target) != '.' ? dirname($target) . '/' : ''; $info = pathinfo($file->getFileUri()); $resize_file_path = 'public://resize/' . $dirname . $info['filename'] . '-' . $node->getAttribute('width') . 'x' . $node->getAttribute('height') . '.' . $info['extension']; // Checking if the image was already resized: if (file_exists($resize_file_path)) { $node->setAttribute('src', file_url_transform_relative(file_create_url($resize_file_path))); continue; } // Delete this when https://www.drupal.org/node/2211657#comment-11510213 // be fixed. $dirname = $this->fileSystem->dirname($resize_file_path); if (!file_exists($dirname)) { file_prepare_directory($dirname, FILE_CREATE_DIRECTORY); } // Checks if the resize filter exists if is not then create it. $copy = file_unmanaged_copy($file->getFileUri(), $resize_file_path, FILE_EXISTS_REPLACE); $copy_image = $this->imageFactory->get($copy); $copy_image->resize($node->getAttribute('width'), $node->getAttribute('height')); $copy_image->save(); $node->setAttribute('src', file_url_transform_relative(file_create_url($copy))); } return Html::serialize($dom); }
/** * Determines if the given URI or path is considered local. * * A URI or path is considered local if it either has no scheme component, * or the scheme is implemented by a stream wrapper which extends * \Drupal\Core\StreamWrapper\LocalStream. * * @param string $uri * The URI or path to test. * * @return bool */ protected function isLocalUri($uri) { $scheme = $this->fileSystem->uriScheme($uri); return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream; }
/** * Gets the path to the library. * * @return string * The path to the library. * * @throws \Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException */ public function getLibraryPath() { // @todo Validate that the library is installed without causing infinite // recursion. return $this->fileSystemHelper->realpath($this->getUri()); }