{
protected $entityRepo;
+ protected $imageService;
/**
* ExportService constructor.
* @param $entityRepo
*/
- public function __construct(EntityRepo $entityRepo)
+ public function __construct(EntityRepo $entityRepo, ImageService $imageService)
{
$this->entityRepo = $entityRepo;
+ $this->imageService = $imageService;
}
/**
* Includes required CSS & image content. Images are base64 encoded into the HTML.
* @param Page $page
* @return mixed|string
+ * @throws \Throwable
*/
public function pageToContainedHtml(Page $page)
{
* Convert a chapter to a self-contained HTML file.
* @param Chapter $chapter
* @return mixed|string
+ * @throws \Throwable
*/
public function chapterToContainedHtml(Chapter $chapter)
{
* Convert a book to a self-contained HTML file.
* @param Book $book
* @return mixed|string
+ * @throws \Throwable
*/
public function bookToContainedHtml(Book $book)
{
* Convert a page to a PDF file.
* @param Page $page
* @return mixed|string
+ * @throws \Throwable
*/
public function pageToPdf(Page $page)
{
* Convert a chapter to a PDF file.
* @param Chapter $chapter
* @return mixed|string
+ * @throws \Throwable
*/
public function chapterToPdf(Chapter $chapter)
{
* Convert a book to a PDF file
* @param Book $book
* @return string
+ * @throws \Throwable
*/
public function bookToPdf(Book $book)
{
* Convert normal webpage HTML to a PDF.
* @param $html
* @return string
+ * @throws \Exception
*/
protected function htmlToPdf($html)
{
// Replace image src with base64 encoded image strings
if (isset($imageTagsOutput[0]) && count($imageTagsOutput[0]) > 0) {
foreach ($imageTagsOutput[0] as $index => $imgMatch) {
- $oldImgString = $imgMatch;
+ $oldImgTagString = $imgMatch;
$srcString = $imageTagsOutput[2][$index];
- $isLocal = strpos(trim($srcString), 'http') !== 0;
- if ($isLocal) {
- $pathString = public_path(trim($srcString, '/'));
- } else {
- $pathString = $srcString;
- }
-
- // Attempt to find local files even if url not absolute
- $base = baseUrl('/');
- if (strpos($srcString, $base) === 0) {
- $isLocal = true;
- $relString = str_replace($base, '', $srcString);
- $pathString = public_path(trim($relString, '/'));
- }
-
- if ($isLocal && !file_exists($pathString)) {
- continue;
- }
- try {
- if ($isLocal) {
- $imageContent = file_get_contents($pathString);
- } else {
- $ch = curl_init();
- curl_setopt_array($ch, [CURLOPT_URL => $pathString, CURLOPT_RETURNTRANSFER => 1, CURLOPT_CONNECTTIMEOUT => 5]);
- $imageContent = curl_exec($ch);
- $err = curl_error($ch);
- curl_close($ch);
- if ($err) {
- throw new \Exception("Image fetch failed, Received error: " . $err);
- }
- }
- $imageEncoded = 'data:image/' . pathinfo($pathString, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageContent);
- $newImageString = str_replace($srcString, $imageEncoded, $oldImgString);
- } catch (\ErrorException $e) {
- $newImageString = '';
+ $imageEncoded = $this->imageService->imageUriToBase64($srcString);
+ if ($imageEncoded === null) {
+ $imageEncoded = $srcString;
}
- $htmlContent = str_replace($oldImgString, $newImageString, $htmlContent);
+ $newImgTagString = str_replace($srcString, $imageEncoded, $oldImgTagString);
+ $htmlContent = str_replace($oldImgTagString, $newImgTagString, $htmlContent);
}
}
return $image;
}
+ /**
+ * Convert a image URI to a Base64 encoded string.
+ * Attempts to find locally via set storage method first.
+ * @param string $uri
+ * @return null|string
+ * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
+ */
+ public function imageUriToBase64(string $uri)
+ {
+ $isLocal = strpos(trim($uri), 'http') !== 0;
+
+ // Attempt to find local files even if url not absolute
+ $base = baseUrl('/');
+ if (!$isLocal && strpos($uri, $base) === 0) {
+ $isLocal = true;
+ $uri = str_replace($base, '', $uri);
+ }
+
+ $imageData = null;
+
+ if ($isLocal) {
+ $uri = trim($uri, '/');
+ $storage = $this->getStorage();
+ if ($storage->exists($uri)) {
+ $imageData = $storage->get($uri);
+ }
+ } else {
+ try {
+ $ch = curl_init();
+ curl_setopt_array($ch, [CURLOPT_URL => $uri, CURLOPT_RETURNTRANSFER => 1, CURLOPT_CONNECTTIMEOUT => 5]);
+ $imageData = curl_exec($ch);
+ $err = curl_error($ch);
+ curl_close($ch);
+ if ($err) {
+ throw new \Exception("Image fetch failed, Received error: " . $err);
+ }
+ } catch (\Exception $e) {}
+ }
+
+ if ($imageData === null) {
+ return null;
+ }
+
+ return 'data:image/' . pathinfo($uri, PATHINFO_EXTENSION) . ';base64,' . base64_encode($imageData);
+ }
+
/**
* Gets a public facing url for an image by checking relevant environment variables.
* @param string $filePath
}
}
+ public function test_secure_images_included_in_exports()
+ {
+ config()->set('filesystems.default', 'local_secure');
+ $this->asEditor();
+ $galleryFile = $this->getTestImage('my-secure-test-upload');
+ $page = Page::first();
+ $expectedPath = storage_path('uploads/images/gallery/' . Date('Y-m-M') . '/my-secure-test-upload');
+
+ $upload = $this->call('POST', '/images/gallery/upload', ['uploaded_to' => $page->id], [], ['file' => $galleryFile], []);
+ $imageUrl = json_decode($upload->getContent(), true)['url'];
+ $page->html .= "<img src=\"{$imageUrl}\">";
+ $page->save();
+ $upload->assertStatus(200);
+
+ $encodedImageContent = base64_encode(file_get_contents($expectedPath));
+ $export = $this->get($page->getUrl('/export/html'));
+ $this->assertTrue(str_contains($export->getContent(), $encodedImageContent), 'Uploaded image in export content');
+
+ if (file_exists($expectedPath)) {
+ unlink($expectedPath);
+ }
+ }
+
public function test_system_images_remain_public()
{
config()->set('filesystems.default', 'local_secure');