Upgrade to Laravel 13 #90

Merged
jonny merged 1 commit from laravel_13 into develop 2026-04-07 10:02:41 +02:00
117 changed files with 1878 additions and 2215 deletions

View file

@ -70,11 +70,6 @@ ADMIN_USER=admin# pick something better, this is used for `/admin`
ADMIN_PASS=password ADMIN_PASS=password
DISPLAY_NAME='Joe Bloggs'# This is used for example in the header and titles DISPLAY_NAME='Joe Bloggs'# This is used for example in the header and titles
TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
TWITTER_ACCESS_TOKEN=
TWITTER_ACCESS_TOKEN_SECRET=
SCOUT_DRIVER=database SCOUT_DRIVER=database
SCOUT_QUEUE=false SCOUT_QUEUE=false

View file

@ -28,10 +28,10 @@ class MentionRenderer implements NodeRendererInterface
// This is not [@]handle@instance, so return a Twitter link // This is not [@]handle@instance, so return a Twitter link
if (count($parts) === 1) { if (count($parts) === 1) {
return new HtmlElement('a', ['href' => 'https://twitter.com/' . $parts[0]], '@' . $mentionText); return new HtmlElement('a', ['href' => 'https://twitter.com/'.$parts[0]], '@'.$mentionText);
} }
// Render the Mastodon profile link // Render the Mastodon profile link
return new HtmlElement('a', ['href' => 'https://' . $parts[1] . '/@' . $parts[0]], '@' . $mentionText); return new HtmlElement('a', ['href' => 'https://'.$parts[1].'/@'.$parts[0]], '@'.$mentionText);
} }
} }

View file

@ -34,10 +34,10 @@ class CopyMediaToLocal extends Command
foreach ($media as $mediaItem) { foreach ($media as $mediaItem) {
$filename = $mediaItem->path; $filename = $mediaItem->path;
$this->info('Processing: ' . $filename); $this->info('Processing: '.$filename);
// If the file is already saved locally skip to next one // If the file is already saved locally skip to next one
if (Storage::disk('local')->exists('public/' . $filename)) { if (Storage::disk('local')->exists('public/'.$filename)) {
$this->info('File already exists locally, skipping'); $this->info('File already exists locally, skipping');
continue; continue;
@ -50,19 +50,19 @@ class CopyMediaToLocal extends Command
continue; continue;
} }
$contents = Storage::disk('s3')->get($filename); $contents = Storage::disk('s3')->get($filename);
Storage::disk('local')->put('public/' . $filename, $contents); Storage::disk('local')->put('public/'.$filename, $contents);
// Copy -medium and -small versions if they exist // Copy -medium and -small versions if they exist
$filenameParts = explode('.', $filename); $filenameParts = explode('.', $filename);
$extension = array_pop($filenameParts); $extension = array_pop($filenameParts);
$basename = trim(implode('.', $filenameParts), '.'); $basename = trim(implode('.', $filenameParts), '.');
$mediumFilename = $basename . '-medium.' . $extension; $mediumFilename = $basename.'-medium.'.$extension;
$smallFilename = $basename . '-small.' . $extension; $smallFilename = $basename.'-small.'.$extension;
if (Storage::disk('s3')->exists($mediumFilename)) { if (Storage::disk('s3')->exists($mediumFilename)) {
Storage::disk('local')->put('public/' . $mediumFilename, Storage::disk('s3')->get($mediumFilename)); Storage::disk('local')->put('public/'.$mediumFilename, Storage::disk('s3')->get($mediumFilename));
} }
if (Storage::disk('s3')->exists($smallFilename)) { if (Storage::disk('s3')->exists($smallFilename)) {
Storage::disk('local')->put('public/' . $smallFilename, Storage::disk('s3')->get($smallFilename)); Storage::disk('local')->put('public/'.$smallFilename, Storage::disk('s3')->get($smallFilename));
} }
} }
} }

View file

@ -63,7 +63,7 @@ class MigratePlaceDataFromPostgis extends Command
$places = Place::all(); $places = Place::all();
$places->each(function ($place) { $places->each(function ($place) {
$this->info('Extracting Postgis data for place: ' . $place->name); $this->info('Extracting Postgis data for place: '.$place->name);
$place->latitude = $place->location->getLat(); $place->latitude = $place->location->getLat();
$place->longitude = $place->location->getLng(); $place->longitude = $place->location->getLng();

View file

@ -32,11 +32,11 @@ class ParseCachedWebMentions extends Command
*/ */
public function handle(FileSystem $filesystem): void public function handle(FileSystem $filesystem): void
{ {
$htmlFiles = $filesystem->allFiles(storage_path() . '/HTML'); $htmlFiles = $filesystem->allFiles(storage_path().'/HTML');
foreach ($htmlFiles as $file) { foreach ($htmlFiles as $file) {
if ($file->getExtension() !== 'backup') { // we don’t want to parse `.backup` files if ($file->getExtension() !== 'backup') { // we don’t want to parse `.backup` files
$filepath = $file->getPathname(); $filepath = $file->getPathname();
$this->info('Loading HTML from: ' . $filepath); $this->info('Loading HTML from: '.$filepath);
$html = $filesystem->get($filepath); $html = $filesystem->get($filepath);
$url = $this->urlFromFilename($filepath); $url = $this->urlFromFilename($filepath);
$webmention = WebMention::where('source', $url)->firstOrFail(); $webmention = WebMention::where('source', $url)->firstOrFail();
@ -53,7 +53,7 @@ class ParseCachedWebMentions extends Command
*/ */
private function urlFromFilename(string $filepath): string private function urlFromFilename(string $filepath): string
{ {
$dir = mb_substr($filepath, mb_strlen(storage_path() . '/HTML/')); $dir = mb_substr($filepath, mb_strlen(storage_path().'/HTML/'));
$url = str_replace(['http/', 'https/'], ['http://', 'https://'], $dir); $url = str_replace(['http/', 'https/'], ['http://', 'https://'], $dir);
if (mb_substr($url, -10) === 'index.html') { if (mb_substr($url, -10) === 'index.html') {
$url = mb_substr($url, 0, -10); $url = mb_substr($url, 0, -10);

View file

@ -31,7 +31,7 @@ class ReDownloadWebMentions extends Command
{ {
$webmentions = WebMention::all(); $webmentions = WebMention::all();
foreach ($webmentions as $webmention) { foreach ($webmentions as $webmention) {
$this->info('Initiation re-download of ' . $webmention->source); $this->info('Initiation re-download of '.$webmention->source);
dispatch(new DownloadWebMention($webmention->source)); dispatch(new DownloadWebMention($webmention->source));
} }
} }

View file

@ -7,6 +7,7 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Contact; use App\Models\Contact;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use Illuminate\Filesystem\Filesystem; use Illuminate\Filesystem\Filesystem;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
@ -75,7 +76,7 @@ class ContactsController extends Controller
if (request()->hasFile('avatar') && (request()->input('homepage') != '')) { if (request()->hasFile('avatar') && (request()->input('homepage') != '')) {
$dir = parse_url(request()->input('homepage'), PHP_URL_HOST); $dir = parse_url(request()->input('homepage'), PHP_URL_HOST);
$destination = public_path() . '/assets/profile-images/' . $dir; $destination = public_path().'/assets/profile-images/'.$dir;
$filesystem = new Filesystem; $filesystem = new Filesystem;
if ($filesystem->isDirectory($destination) === false) { if ($filesystem->isDirectory($destination) === false) {
$filesystem->makeDirectory($destination); $filesystem->makeDirectory($destination);
@ -103,7 +104,7 @@ class ContactsController extends Controller
* This method attempts to find the microformat marked-up profile image * This method attempts to find the microformat marked-up profile image
* from a given homepage and save it accordingly * from a given homepage and save it accordingly
* *
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View * @return RedirectResponse|View
*/ */
public function getAvatar(int $contactId) public function getAvatar(int $contactId)
{ {
@ -115,8 +116,8 @@ class ContactsController extends Controller
$client = resolve(Client::class); $client = resolve(Client::class);
try { try {
$response = $client->get($contact->homepage); $response = $client->get($contact->homepage);
} catch (\GuzzleHttp\Exception\BadResponseException $e) { } catch (BadResponseException $e) {
return redirect('/admin/contacts/' . $contactId . '/edit') return redirect('/admin/contacts/'.$contactId.'/edit')
->with('error', 'Bad resposne from contact’s homepage'); ->with('error', 'Bad resposne from contact’s homepage');
} }
$mf2 = \Mf2\parse((string) $response->getBody(), $contact->homepage); $mf2 = \Mf2\parse((string) $response->getBody(), $contact->homepage);
@ -129,18 +130,18 @@ class ContactsController extends Controller
if ($avatarURL !== null) { if ($avatarURL !== null) {
try { try {
$avatar = $client->get($avatarURL); $avatar = $client->get($avatarURL);
} catch (\GuzzleHttp\Exception\BadResponseException $e) { } catch (BadResponseException $e) {
return redirect('/admin/contacts/' . $contactId . '/edit') return redirect('/admin/contacts/'.$contactId.'/edit')
->with('error', 'Unable to download avatar'); ->with('error', 'Unable to download avatar');
} }
} }
if ($avatar !== null) { if ($avatar !== null) {
$directory = public_path() . '/assets/profile-images/' . parse_url($contact->homepage, PHP_URL_HOST); $directory = public_path().'/assets/profile-images/'.parse_url($contact->homepage, PHP_URL_HOST);
$filesystem = new Filesystem; $filesystem = new Filesystem;
if ($filesystem->isDirectory($directory) === false) { if ($filesystem->isDirectory($directory) === false) {
$filesystem->makeDirectory($directory); $filesystem->makeDirectory($directory);
} }
$filesystem->put($directory . '/image', $avatar->getBody()); $filesystem->put($directory.'/image', $avatar->getBody());
return view('admin.contacts.getavatarsuccess', [ return view('admin.contacts.getavatarsuccess', [
'homepage' => parse_url($contact->homepage, PHP_URL_HOST), 'homepage' => parse_url($contact->homepage, PHP_URL_HOST),
@ -148,6 +149,6 @@ class ContactsController extends Controller
} }
} }
return redirect('/admin/contacts/' . $contactId . '/edit'); return redirect('/admin/contacts/'.$contactId.'/edit');
} }
} }

View file

@ -128,7 +128,7 @@ class PasskeysController extends Controller
// Unset session data to mitigate replay attacks // Unset session data to mitigate replay attacks
$request->session()->forget('create_options'); $request->session()->forget('create_options');
if (empty($publicKeyCredentialCreationOptionsData)) { if (empty($publicKeyCredentialCreationOptionsData)) {
throw new WebAuthnException('No public key credential request options found'); throw new WebauthnException('No public key credential request options found');
} }
$attestationStatementSupportManager = new AttestationStatementSupportManager; $attestationStatementSupportManager = new AttestationStatementSupportManager;
@ -145,7 +145,7 @@ class PasskeysController extends Controller
); );
if (! $publicKeyCredential->response instanceof AuthenticatorAttestationResponse) { if (! $publicKeyCredential->response instanceof AuthenticatorAttestationResponse) {
throw new WebAuthnException('Invalid response type'); throw new WebauthnException('Invalid response type');
} }
$algorithmManager = new Manager; $algorithmManager = new Manager;

View file

@ -120,6 +120,7 @@ class PlacesController extends Controller
foreach ($place1->notes as $note) { foreach ($place1->notes as $note) {
$note->place()->dissociate(); $note->place()->dissociate();
$note->place()->associate($place2->id); $note->place()->associate($place2->id);
$note->save();
} }
$place1->delete(); $place1->delete();
} }
@ -127,6 +128,7 @@ class PlacesController extends Controller
foreach ($place2->notes as $note) { foreach ($place2->notes as $note) {
$note->place()->dissociate(); $note->place()->dissociate();
$note->place()->associate($place1->id); $note->place()->associate($place1->id);
$note->save();
} }
$place2->delete(); $place2->delete();
} }

View file

@ -38,9 +38,9 @@ class ArticlesController extends Controller
if ($article->updated_at->year != $year || $article->updated_at->month != $month) { if ($article->updated_at->year != $year || $article->updated_at->month != $month) {
return redirect('/blog/' return redirect('/blog/'
. $article->updated_at->year .$article->updated_at->year
. '/' . $article->updated_at->format('m') .'/'.$article->updated_at->format('m')
. '/' . $slug); .'/'.$slug);
} }
return view('articles.show', compact('article')); return view('articles.show', compact('article'));

View file

@ -19,9 +19,9 @@ class ContactsController extends Controller
$contacts = Contact::all(); $contacts = Contact::all();
foreach ($contacts as $contact) { foreach ($contacts as $contact) {
$contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST); $contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST);
$file = public_path() . '/assets/profile-images/' . $contact->homepageHost . '/image'; $file = public_path().'/assets/profile-images/'.$contact->homepageHost.'/image';
$contact->image = ($filesystem->exists($file)) ? $contact->image = ($filesystem->exists($file)) ?
'/assets/profile-images/' . $contact->homepageHost . '/image' '/assets/profile-images/'.$contact->homepageHost.'/image'
: :
'/assets/profile-images/default-image'; '/assets/profile-images/default-image';
} }
@ -35,11 +35,11 @@ class ContactsController extends Controller
public function show(Contact $contact): View public function show(Contact $contact): View
{ {
$contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST); $contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST);
$file = public_path() . '/assets/profile-images/' . $contact->homepageHost . '/image'; $file = public_path().'/assets/profile-images/'.$contact->homepageHost.'/image';
$filesystem = new Filesystem; $filesystem = new Filesystem;
$image = ($filesystem->exists($file)) ? $image = ($filesystem->exists($file)) ?
'/assets/profile-images/' . $contact->homepageHost . '/image' '/assets/profile-images/'.$contact->homepageHost.'/image'
: :
'/assets/profile-images/default-image'; '/assets/profile-images/default-image';

View file

@ -71,9 +71,9 @@ class FeedsController extends Controller
$articles = Article::where('published', '1')->latest('updated_at')->take(20)->get(); $articles = Article::where('published', '1')->latest('updated_at')->take(20)->get();
$data = [ $data = [
'version' => 'https://jsonfeed.org/version/1.1', 'version' => 'https://jsonfeed.org/version/1.1',
'title' => 'The JSON Feed for ' . config('user.display_name') . '’s blog', 'title' => 'The JSON Feed for '.config('user.display_name').'’s blog',
'home_page_url' => config('app.url') . '/blog', 'home_page_url' => config('app.url').'/blog',
'feed_url' => config('app.url') . '/blog/feed.json', 'feed_url' => config('app.url').'/blog/feed.json',
'authors' => [ 'authors' => [
[ [
'name' => config('user.display_name'), 'name' => config('user.display_name'),
@ -85,9 +85,9 @@ class FeedsController extends Controller
foreach ($articles as $key => $article) { foreach ($articles as $key => $article) {
$data['items'][$key] = [ $data['items'][$key] = [
'id' => config('app.url') . $article->link, 'id' => config('app.url').$article->link,
'title' => $article->title, 'title' => $article->title,
'url' => config('app.url') . $article->link, 'url' => config('app.url').$article->link,
'content_html' => $article->main, 'content_html' => $article->main,
'date_published' => $article->created_at->tz('UTC')->toRfc3339String(), 'date_published' => $article->created_at->tz('UTC')->toRfc3339String(),
'date_modified' => $article->updated_at->tz('UTC')->toRfc3339String(), 'date_modified' => $article->updated_at->tz('UTC')->toRfc3339String(),
@ -105,9 +105,9 @@ class FeedsController extends Controller
$notes = Note::latest()->with('media', 'place', 'tags')->take(20)->get(); $notes = Note::latest()->with('media', 'place', 'tags')->take(20)->get();
$data = [ $data = [
'version' => 'https://jsonfeed.org/version/1.1', 'version' => 'https://jsonfeed.org/version/1.1',
'title' => 'The JSON Feed for ' . config('user.display_name') . '’s notes', 'title' => 'The JSON Feed for '.config('user.display_name').'’s notes',
'home_page_url' => config('app.url') . '/notes', 'home_page_url' => config('app.url').'/notes',
'feed_url' => config('app.url') . '/notes/feed.json', 'feed_url' => config('app.url').'/notes/feed.json',
'authors' => [ 'authors' => [
[ [
'name' => config('user.display_name'), 'name' => config('user.display_name'),
@ -144,8 +144,8 @@ class FeedsController extends Controller
$items[] = [ $items[] = [
'type' => 'entry', 'type' => 'entry',
'published' => $article->created_at, 'published' => $article->created_at,
'uid' => config('app.url') . $article->link, 'uid' => config('app.url').$article->link,
'url' => config('app.url') . $article->link, 'url' => config('app.url').$article->link,
'content' => [ 'content' => [
'text' => $article->main, 'text' => $article->main,
'html' => $article->html, 'html' => $article->html,
@ -156,7 +156,7 @@ class FeedsController extends Controller
return response()->json([ return response()->json([
'type' => 'feed', 'type' => 'feed',
'name' => 'Blog feed for ' . config('app.name'), 'name' => 'Blog feed for '.config('app.name'),
'url' => url('/blog'), 'url' => url('/blog'),
'author' => [ 'author' => [
'type' => 'card', 'type' => 'card',
@ -192,7 +192,7 @@ class FeedsController extends Controller
return response()->json([ return response()->json([
'type' => 'feed', 'type' => 'feed',
'name' => 'Notes feed for ' . config('app.name'), 'name' => 'Notes feed for '.config('app.name'),
'url' => url('/notes'), 'url' => url('/notes'),
'author' => [ 'author' => [
'type' => 'card', 'type' => 'card',

View file

@ -193,7 +193,7 @@ class MicropubMediaController extends Controller
*/ */
private function saveFileToLocal(UploadedFile $file): string private function saveFileToLocal(UploadedFile $file): string
{ {
$filename = Uuid::uuid4()->toString() . '.' . $file->extension(); $filename = Uuid::uuid4()->toString().'.'.$file->extension();
Storage::disk('local')->putFileAs('', $file, $filename); Storage::disk('local')->putFileAs('', $file, $filename);
return $filename; return $filename;

View file

@ -64,7 +64,7 @@ class NotesController extends Controller
*/ */
public function redirect(int $decId): RedirectResponse public function redirect(int $decId): RedirectResponse
{ {
return redirect(config('app.url') . '/notes/' . (new Numbers)->numto60($decId)); return redirect(config('app.url').'/notes/'.(new Numbers)->numto60($decId));
} }
/** /**

View file

@ -14,11 +14,11 @@ class LinkHeadersMiddleware
public function handle(Request $request, Closure $next): Response public function handle(Request $request, Closure $next): Response
{ {
$response = $next($request); $response = $next($request);
$response->header('Link', '<' . route('indieauth.metadata') . '>; rel="indieauth-metadata"', false); $response->header('Link', '<'.route('indieauth.metadata').'>; rel="indieauth-metadata"', false);
$response->header('Link', '<' . route('indieauth.start') . '>; rel="authorization_endpoint"', false); $response->header('Link', '<'.route('indieauth.start').'>; rel="authorization_endpoint"', false);
$response->header('Link', '<' . route('indieauth.token') . '>; rel="token_endpoint"', false); $response->header('Link', '<'.route('indieauth.token').'>; rel="token_endpoint"', false);
$response->header('Link', '<' . route('micropub-endpoint') . '>; rel="micropub"', false); $response->header('Link', '<'.route('micropub-endpoint').'>; rel="micropub"', false);
$response->header('Link', '<' . route('webmention-endpoint') . '>; rel="webmention"', false); $response->header('Link', '<'.route('webmention-endpoint').'>; rel="webmention"', false);
return $response; return $response;
} }

View file

@ -16,7 +16,7 @@ class RedirectIfAuthenticated
/** /**
* Handle an incoming request. * Handle an incoming request.
* *
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next * @param Closure(Request): (Response) $next
*/ */
public function handle(Request $request, Closure $next, string ...$guards): Response public function handle(Request $request, Closure $next, string ...$guards): Response
{ {

View file

@ -39,9 +39,9 @@ class DownloadWebMention implements ShouldQueue
// Laravel should catch and retry these automatically. // Laravel should catch and retry these automatically.
if ($response->getStatusCode() === 200) { if ($response->getStatusCode() === 200) {
$filesystem = new FileSystem; $filesystem = new FileSystem;
$filename = storage_path('HTML') . '/' . $this->createFilenameFromURL($this->source); $filename = storage_path('HTML').'/'.$this->createFilenameFromURL($this->source);
// backup file first // backup file first
$filenameBackup = $filename . '.' . date('Y-m-d') . '.backup'; $filenameBackup = $filename.'.'.date('Y-m-d').'.backup';
if ($filesystem->exists($filename)) { if ($filesystem->exists($filename)) {
$filesystem->copy($filename, $filenameBackup); $filesystem->copy($filename, $filenameBackup);
} }

View file

@ -5,10 +5,8 @@ declare(strict_types=1);
namespace App\Jobs; namespace App\Jobs;
use App\Models\Like; use App\Models\Like;
use Codebird\Codebird;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
@ -39,35 +37,6 @@ class ProcessLike implements ShouldQueue
*/ */
public function handle(Client $client, Authorship $authorship): int public function handle(Client $client, Authorship $authorship): int
{ {
if ($this->isTweet($this->like->url)) {
$codebird = resolve(Codebird::class);
$tweet = $codebird->statuses_oembed(['url' => $this->like->url]);
$this->like->author_name = $tweet->author_name;
$this->like->author_url = $tweet->author_url;
$this->like->content = $tweet->html;
$this->like->save();
// POSSE like
try {
$client->request(
'POST',
'https://brid.gy/publish/webmention',
[
'form_params' => [
'source' => $this->like->url,
'target' => 'https://brid.gy/publish/twitter',
],
]
);
} catch (RequestException) {
return 0;
}
return 0;
}
$response = $client->request('GET', $this->like->url); $response = $client->request('GET', $this->like->url);
$mf2 = \Mf2\parse((string) $response->getBody(), $this->like->url); $mf2 = \Mf2\parse((string) $response->getBody(), $this->like->url);
if (Arr::has($mf2, 'items.0.properties.content')) { if (Arr::has($mf2, 'items.0.properties.content')) {
@ -91,15 +60,4 @@ class ProcessLike implements ShouldQueue
return 0; return 0;
} }
/**
* Determine if a given URL is that of a Tweet.
*/
private function isTweet(string $url): bool
{
$host = parse_url($url, PHP_URL_HOST);
$parts = array_reverse(explode('.', $host));
return $parts[0] === 'com' && $parts[1] === 'twitter';
}
} }

View file

@ -57,10 +57,10 @@ class ProcessMedia implements ShouldQueue
$basename = trim(implode('.', $filenameParts), '.'); $basename = trim(implode('.', $filenameParts), '.');
$medium = $image->resize(width: 1000); $medium = $image->resize(width: 1000);
Storage::disk('public')->put($basename . '-medium.' . $extension, (string) $medium->encode()); Storage::disk('public')->put($basename.'-medium.'.$extension, (string) $medium->encode());
$small = $image->resize(width: 500); $small = $image->resize(width: 500);
Storage::disk('public')->put($basename . '-small.' . $extension, (string) $small->encode()); Storage::disk('public')->put($basename.'-small.'.$extension, (string) $small->encode());
} }
// Now we can delete the locally saved image // Now we can delete the locally saved image

View file

@ -110,7 +110,7 @@ class ProcessWebMention implements ShouldQueue
if (str_ends_with($url, '/')) { if (str_ends_with($url, '/')) {
$filenameFromURL .= 'index.html'; $filenameFromURL .= 'index.html';
} }
$path = storage_path() . '/HTML/' . $filenameFromURL; $path = storage_path().'/HTML/'.$filenameFromURL;
$parts = explode('/', $path); $parts = explode('/', $path);
$name = array_pop($parts); $name = array_pop($parts);
$dir = implode('/', $parts); $dir = implode('/', $parts);

Some files were not shown because too many files have changed in this diff Show more