Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning rendered blade component causes file_exists to fail on some systems #32254

Closed
raitisg opened this issue Apr 6, 2020 · 13 comments
Closed

Comments

@raitisg
Copy link

raitisg commented Apr 6, 2020

  • Laravel Version: 7.4.0
  • PHP Version: 7.2.28
  • Database Driver & Version:

Description:

When Component class returns string (html), resolveView() checks if such file exists before creating view from string. If component's content is large enough, exception is thrown: file_exists(): File name is longer than the maximum allowed path length on this platform (4096): /path/to/html-string-...

Steps To Reproduce:

Create component class:

public function render() {
    return str_repeat('a', 99999);
    // or (more realistically):
    // return view('components.my-component')->render();
}
@raitisg raitisg changed the title Returning rendered components causes file_exists to fail on some systems Returning rendered blade component causes file_exists to fail on some systems Apr 6, 2020
@driesvints
Copy link
Member

Can you please share the exact code that's causing this?

@raitisg
Copy link
Author

raitisg commented Apr 7, 2020

src/Illuminate/View/Component.php:64

return $factory->exists($view)
            ? $view
            : $this->createBladeViewFromString($factory, $view);

$view in this case would be aaa....aaa (or my more realistic scenario <div>html of a component</div>).

@driesvints
Copy link
Member

Please share your own code that's causing this.

@raitisg
Copy link
Author

raitisg commented Apr 7, 2020

Create blade component:

php artisan make:component Foobar

app/View/Components/Foobar.php:

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Foobar extends Component
{
	public function render() {
		return str_repeat('a', 9999);
	}
}

routes/web.php:

Route::get('/component-test', function(){
	return view('component');
});

resources/views/component.blade.php:

<h1>Component</h1>

<x-foobar/>

Opening /component-test throws error:

file_exists(): File name is longer than the maximum allowed path length on this platform (4096): /absolute/path/to/resources/views/aaaaaaaaaaaaaaaaaaaa...

This error only occurs on production server (Ubuntu). On my local dev machine (MacOS) everything works fine, but the problem remains: Laravel calls file_exists with component's content as first argument before trying to compile it.

@driesvints
Copy link
Member

Is there any reason at all why you can't place the contents in a view?

@raitisg
Copy link
Author

raitisg commented Apr 7, 2020

I am placing it in a view, this is a simplified example. My render function looks more like this:

public function render() {
	return view('components.foobar')->render();
}

I'm doing this for custom caching purposes. Main point still stands - I'm returning a string. Docs make it clear returning either string or a View is fine, but doesn't mention anywhere that string could also be a filepath and not just plain content.

@driesvints
Copy link
Member

@raitisg you don't need the render method above. Feel free to pr to the docs if you want to clarify anything. Thanks.

@raitisg
Copy link
Author

raitisg commented Apr 7, 2020

It was a simplified example. Yes - in this specific scenario it is indeed not needed, but that is beyond the point. My actual code does more and I can not return View - only string.

Documentation states:

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.alert');
    }

Which is not entirely true. Returning contents can throw this error. You can also return view filename which is not mentioned.

@driesvints
Copy link
Member

@raitisg it's true that contents can throw this error but in that case you should really just place the contents in a view.

@f-liva
Copy link

f-liva commented Nov 2, 2020

There is any solution?

@bernhardh
Copy link

bernhardh commented Jul 29, 2021

Any solution yet? The content comes from database, so it has to be string, not a view. Tried the Htmlable workaround, but then livewire components inside the string doesn't work anymore.

@madbob
Copy link

madbob commented Jul 5, 2022

This is not fixed: the solution merged in #41956 is a bit too optimistic and do not considers the length of paths concatenated to the components' rendered strings (more exactly in FileViewFinder::findInPaths()), so the resulting path coming to Filesystem::exists() may still be longer than PHP_MAXPATHLEN.

A definitive solution may be to test the length of every string in Filesystem::exists(), but this may have dramatic conseguences on performances.
Another solution may be to test the length of $viewPath in FileViewFinder::findInPaths() before passing it to Filesystem::exists(): easy and not invasive.
An even more articulated solution may be to target exactly the specific case of a Component's rendered string (which is probably the only situation in which a long string is tested to be a filesystem path) and provide an ad-hoc test in Component::resolveView() (or more exactly in Illuminate\View\Factory) to limit the impact of this check.

Opinions?

@bernhardh
Copy link

This is still an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants