[RESOLU] Mon image ne s'affiche plus avec TinyMCE

Eléphant du PHP | 74 Messages

21 mars 2024, 09:49

S'il vous plaît, quelqu'un pourrait-il m'aider à configurer correctement mon TinyMCE ? Mes images se stockent bien dans mon dossier mais ne s'affichent pas... J'obtiens une erreur 404. Il y a deux jours, tout fonctionnait bien.

GET http://127.0.0.1:8000/guide/assets/imag ... e3fdac.png 404 (Not Found)

Le fichier se trouve bien dans le dossier assets/images pourtant, je le vois bien !

SVP :(

<?php

/***************************************************
 * Only these origins are allowed to upload images *
 ***************************************************/
$accepted_origins = array("http://127.0.0.1:8000");

/*********************************************
 * Change this line to set the upload folder *
 *********************************************/
$imageFolder = "assets/images/";
$name = uniqid();

if (isset($_SERVER['HTTP_ORIGIN'])) {
  // same-origin requests won't set an origin. If the origin is set, it must be valid.
  if (in_array($_SERVER['HTTP_ORIGIN'], $accepted_origins)) {
    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
  } else {
    header("HTTP/1.1 403 Origin Denied");
    return;
  }
}

// Don't attempt to process the upload on an OPTIONS request
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  header("Access-Control-Allow-Methods: POST, OPTIONS");
  return;
}

reset($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])) {
  /*
      If your script needs to receive cookies, set images_upload_credentials : true in
      the configuration and enable the following two headers.
    */
  // header('Access-Control-Allow-Credentials: true');
  // header('P3P: CP="There is no P3P policy."');

  // Sanitize input
  if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
    header("HTTP/1.1 400 Invalid file name.");
    return;
  }

  // Verify extension
  if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
    header("HTTP/1.1 400 Invalid extension.");
    return;
  }

  // Accept upload if there was no origin, or if it is an accepted origin
  // assets/images/
  $extension = pathinfo($temp['name'], PATHINFO_EXTENSION);
  $filetowrite = $imageFolder . $name . "." . $extension;
  move_uploaded_file($temp['tmp_name'], $filetowrite);

  // Determine the base URL
  $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https://" : "http://";
  $baseurl = $protocol . $_SERVER["HTTP_HOST"] . rtrim(dirname($_SERVER['REQUEST_URI']), "/") . "/";

  // Respond to the successful upload with JSON.
  // Use a location key to specify the path to the saved image resource.
  // { location : '/your/uploaded/image/file'}
  echo json_encode(array('location' => $filetowrite));
} else {
  // Notify editor that the upload failed
  header("HTTP/1.1 500 Server Error");
}


{% extends '@EasyAdmin/crud/form_theme.html.twig' %}

{% block ea_text_editor_widget %}

    <textarea id="{{ id }}" name="Article[contenu]"class="trix-content tinymce" role="textbox">{{ data }}</textarea>

    <script src="{{ asset('assets/bundles/tinymce/ext/tinymce/tinymce.min.js') }}"></script>

    <script src="{{ asset('bundles/tinymce/ext/tinymce-webcomponent.js') }}" type="module"></script>

    <script>
    tinymce.init({
      selector: '.tinymce',
      width: '1000px',
      plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount checklist mediaembed casechange export formatpainter pageembed linkchecker a11ychecker tinymcespellchecker permanentpen powerpaste advtable advcode editimage tinycomments tableofcontents footnotes mergetags autocorrect typography inlinecss',
      toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat',
      tinycomments_mode: 'embedded',
      
      images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.withCredentials = false;
        xhr.open('POST', 'upload.php');

        xhr.upload.onprogress = (e) => {
          progress(e.loaded / e.total * 100);
        };

        xhr.onload = () => {
          if (xhr.status === 403) {
            reject({
              message: 'HTTP Error: ' + xhr.status,
              remove: true
            });
            return;
          }

          if (xhr.status < 200 || xhr.status >= 300) {
            console.log(xhr);
            reject('HTTP Error: ' + xhr.status + ' ' + xhr.statusText);
            return;
          }

          const json = JSON.parse(xhr.responseText);

          if (!json || typeof json.location != 'string') {
            reject('Invalid JSON: ' + xhr.responseText);
            return;
          }

          resolve(json.location);
        };

        xhr.onerror = () => {
          reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
        };

        const formData = new FormData();
        formData.append('file', blobInfo.blob(), blobInfo.filename());

        xhr.send(formData);
      })
    });

    // colocar imagem no tinymce
    const images = document.querySelectorAll('.image');
    images.forEach(image => {
      image.addEventListener('click', event => {
        // tinymce.activeEditor.execCommand('mceInsertContent', false, image.outerHTML);
        tinymce.get('image').execCommand('mceInsertContent', false, image.outerHTML);
        // tinymce.activeEditor.setContent(image.outerHTML);
        console.log(event);
      })
    })
  </script>
{% endblock %}


<?php
 
namespace App\Controller\Admin;
 
use App\Entity\Article;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
 
class ArticleCrudController extends AbstractCrudController
{
    
    public static function getEntityFqcn(): string
    {
        return Article::class;
    }

    public function configureCrud(Crud $crud): Crud
    {
        return $crud
            ->setFormThemes(['@EasyAdmin/crud/form_theme.html.twig', 'admin/articleForm2.html.twig']); // On ajoute un thème pour le formulaire
    }
    
    public function configureFields(string $pageName): iterable
    {
        return [
            TextField::new('titre'),
            TextEditorField::new('contenu'),
            AssociationField::new('sousCategorie') // Champ pour sélectionner une sous-catégorie
                ->setLabel('Sous-catégorie')
                ->setRequired(true),
            DateTimeField::new('createdAt') // Ajout du champ createdAt
                ->setLabel('Date de création')
                ->setRequired(true), // Rendre le champ obligatoire
            // AssociationField::new('categorie') // Champ pour sélectionner une sous-catégorie
            //     ->setLabel('Catégorie')
            //     ->setRequired(true),
        ];
    }
}


Avatar du membre
Mammouth du PHP | 1564 Messages

21 mars 2024, 23:25

Vérifie le chemin vers tes images, le chemin qui est dans le code HTML généré puis tente de trouver la variable "path to image" et le modifier en conséquence.

Eléphant du PHP | 74 Messages

22 mars 2024, 10:17

Bonjour, two3d @two3d !

Alors, du jour au lendemain, ça ne fonctionnait plus car j'avais créé une route vue dans un contrôleur, c'est trop bizarre. Mon chemin est correct, Visual Studio me le propose en l'écrivant... Quand ça marchait, j'affichais le contenu de mon article avec du JavaScript de cette manière-là, et du coup j'ai fait autrement. J'ai créé une nouvelle vue pour les afficher avec un identifiant, par exemple guide/view/guide/34... Alors qu'avec le JS, je n'avais aucun changement d'URL, ce qui n'était pas bon pour l'avenir... Mais ça s'affichait.

Voici mon guide/index.html.twig (y'a mon fameux JS en commentaire)

{% extends 'base.html.twig' %}

{% block title %}Guides{% endblock %}

{% block body %}
<div class="container-guide">
    <div class="sidebar">
        <ul>
            <li>
               <h3>Nos guides techniques</h3>
            </li>
        </ul>
        <br>
        <ul>
            {% for category in categories %}
                <li class="category-item">
                    {{ category.getTitre() }}
                    <ul>
                        {% for subcategory in category.getSousCategories() %}
                            <li class="subcategory-item">&nbsp;{{ subcategory.getTitre() }}</li>
                            <ul>
                                {% for article in subcategory.getArticles() %}
                                    <li class="link-item">
                                        &nbsp;&nbsp;<a href="{{ path('detail_guide', {article:article.id}) }}">
                                            {{article.titre}}
                                            {% if article.isPrive() %}
                                                {% if is_granted('ROLE_USER') or is_granted('ROLE_ADMIN') %}
                                                    {% if article.isPrive() == true %}
                                                        🛡️
                                                    {% endif %}
                                                {% endif %}
                                            {% endif %}
                                        </a>
                                    </li>
                                {% endfor %}
                            </ul>
                        {% endfor %}
                    </ul>
                </li>
            {% endfor %}
        </ul>
    </div>
    <div class="main-content">
        <h3 class="article-title" id="articleTitle">Avez-vous des questions ?<br><br>Parcourez nos guides techniques organisés par catégories et sous-catégories<br>pour trouver les réponses dont vous avez besoin.</h3>
    </div>
</div>

{# <script>
    // Récupérer tous les liens d'article
    const articleLinks = document.querySelectorAll('.article-link');

    // Parcourir chaque lien et ajouter un gestionnaire d'événements de clic
    articleLinks.forEach(link => {
        link.addEventListener('click', function(e) {
            e.preventDefault(); // Empêcher le comportement par défaut du lien

            // Récupérer le titre, le contenu et la date de création de l'article à partir des attributs data
            const articleTitle = this.getAttribute('data-title');
            const articleContent = this.getAttribute('data-article');
            const articleDate = this.getAttribute('data-date');

            // Mettre à jour le titre, le contenu et la date de création de l'article dans la section main-content
            document.getElementById('articleTitle').innerText = articleTitle;
            document.getElementById('articleContent').innerHTML = articleContent;
            document.getElementById('articleDate').innerText = 'Publié le : ' + articleDate;
        });
        
    });
</script> #}

{% endblock %}

Et voici mon guide/view.html.twig (là où s'affiche les contenus)

{% extends 'base.html.twig' %}

{% block title %}Guides{% endblock %}

{% block body %}
<div class="container-guide">
    <div class="sidebar">
        <ul>
            <li>
               <h3>Nos guides techniques</h3>
            </li>
        </ul>
        <br>
        <ul>
{% for category in categories %}
                <li class="category-item">
                    {{ category.getTitre() }}
                    <ul>
                        {% for subcategory in category.getSousCategories() %}
                            <li class="subcategory-item">&nbsp;{{ subcategory.getTitre() }}</li>
                            <ul>
                                {% for article in subcategory.getArticles() %}
                                    <li class="link-item">
                                        &nbsp;&nbsp;<a href="{{ path('detail_guide', {article:article.id}) }}">
                                            {{article.titre}}
                                            {% if article.isPrive() %}
                                                {% if is_granted('ROLE_USER') or is_granted('ROLE_ADMIN') %}
                                                    {% if article.isPrive() == true %}
                                                        🛡️
                                                    {% endif %}
                                                {% endif %}
                                            {% endif %}
                                        </a>
                                    </li>
                                {% endfor %}
                            </ul>
                        {% endfor %}
                    </ul>
                </li>
            {% endfor %}

        </ul>
    </div>
    <div class="main-content">
{% if article %}
    <h3 class="article-title" id="articleTitle">{{article.titre}}</h3>
            <div class="article-content" id="articleContent">{{article.contenu|raw}}</div>
        <div class="article-date" id="articleDate">Publié le : {{ article.createdAt|date('d/m/Y', 'Europe/Paris') }}</div>


{% endif %}
    </div>
</div>

{% endblock %}


Eléphant du PHP | 74 Messages

25 mars 2024, 14:50

Je me permet de up le post, si quelqu'un aurait une idée d'où pourrait venir le problème ? svp

En vous souhaitant une bonne journée

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

25 mars 2024, 16:54

Il faut que tu avances dans ton debugage.

L'url de ton image semble être :
http://127.0.0.1:8000/guide/assets/imag ... e3fdac.png
Donc :
- soit tu n'as pas de routes/règles de réécriture d'url qui s'appliquent, et donc tu vérifies que tu as bien un répertoire "guide" dans lequel il y a un répertoire "assets", dans lequel il y a un répertoire "images", dans lequel il y a un fichier nommé "65e9d63e3fdac.png"
- soit tu as des routes/règles de réécriture d'url en place, et donc il faut que tu vérifies si tu en as une qui s'appliquerait à ton path "/guide/assets/images/" et en conséquence vérifier pourquoi ton image n'est pas accessible.
Quand tout le reste a échoué, lisez le mode d'emploi...

Eléphant du PHP | 74 Messages

25 mars 2024, 20:18

Je suis désolé mais je ne trouve pas l'erreur, ma route, mon url, mon chemin est bien présent...

Avatar du membre
Mammouth du PHP | 1564 Messages

25 mars 2024, 22:02

Est ce que tes dossiers "/guide/assets/images/" existent vraiment et que ton fichier "65e9d63e3fdac.png" est à l'intérieur ?

Eléphant du PHP | 74 Messages

25 mars 2024, 23:03

Oui, comme tu peux le voir.... :'(

Image

Mammouth du PHP | 2703 Messages

25 mars 2024, 23:13

et sans le guide ?
car si / pointe vers guide, le premier répertoire dans l'url est assets

Eléphant du PHP | 74 Messages

25 mars 2024, 23:26

Oui même sans le guide :

Image

Avatar du membre
Mammouth du PHP | 1564 Messages

25 mars 2024, 23:32

Colle ici la partie du code source qui affiche l'image, le code <img...>, le code source généré par le navigateur stp.

Eléphant du PHP | 74 Messages

25 mars 2024, 23:41

Voici mon Upload.php :
<?php

/***************************************************
 * Only these origins are allowed to upload images *
 ***************************************************/
$accepted_origins = array("http://127.0.0.1:8000");

/*********************************************
 * Change this line to set the upload folder *
 *********************************************/
$imageFolder = "assets/images/";
$name = uniqid();

if (isset($_SERVER['HTTP_ORIGIN'])) {
  // same-origin requests won't set an origin. If the origin is set, it must be valid.
  if (in_array($_SERVER['HTTP_ORIGIN'], $accepted_origins)) {
    header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
  } else {
    header("HTTP/1.1 403 Origin Denied");
    return;
  }
}

// Don't attempt to process the upload on an OPTIONS request
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  header("Access-Control-Allow-Methods: POST, OPTIONS");
  return;
}

reset($_FILES);
$temp = current($_FILES);
if (is_uploaded_file($temp['tmp_name'])) {
  /*
      If your script needs to receive cookies, set images_upload_credentials : true in
      the configuration and enable the following two headers.
    */
  // header('Access-Control-Allow-Credentials: true');
  // header('P3P: CP="There is no P3P policy."');

  // Sanitize input
  if (preg_match("/([^\w\s\d\-_~,;:\[\]\(\).])|([\.]{2,})/", $temp['name'])) {
    header("HTTP/1.1 400 Invalid file name.");
    return;
  }

  // Verify extension
  if (!in_array(strtolower(pathinfo($temp['name'], PATHINFO_EXTENSION)), array("gif", "jpg", "png"))) {
    header("HTTP/1.1 400 Invalid extension.");
    return;
  }

  // Accept upload if there was no origin, or if it is an accepted origin
  // assets/images/
  $extension = pathinfo($temp['name'], PATHINFO_EXTENSION);
  $filetowrite = $imageFolder . $name . "." . $extension;
  move_uploaded_file($temp['tmp_name'], $filetowrite);

  // Determine the base URL
  $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https://" : "http://";
  $baseurl = $protocol . $_SERVER["HTTP_HOST"] . rtrim(dirname($_SERVER['REQUEST_URI']), "/") . "/";

  // Respond to the successful upload with JSON.
  // Use a location key to specify the path to the saved image resource.
  // { location : '/your/uploaded/image/file'}
  echo json_encode(array('location' => $filetowrite));
} else {
  // Notify editor that the upload failed
  header("HTTP/1.1 500 Server Error");
}
Mon articleForm2.html.twig (je configure mon TinyMce avec ça)
{% extends '@EasyAdmin/crud/form_theme.html.twig' %}

{% block ea_text_editor_widget %}
    <textarea id="{{ id }}" name="Article[contenu]" class="trix-content tinymce" role="textbox">{{ data }}</textarea>

    <script src="{{ asset('assets/bundles/tinymce/ext/tinymce/tinymce.min.js') }}"></script>
    <script src="{{ asset('bundles/tinymce/ext/tinymce-webcomponent.js') }}" type="module"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.3/html2pdf.bundle.min.js"></script>

    <script>
        tinymce.init({
            selector: '.tinymce',
            width: '1000px',
            plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount checklist mediaembed casechange export formatpainter pageembed linkchecker a11ychecker tinymcespellchecker permanentpen powerpaste advtable advcode editimage tinycomments tableofcontents footnotes mergetags autocorrect typography inlinecss',
            toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table mergetags | addcomment showcomments | spellcheckdialog a11ycheck typography | align lineheight | checklist numlist bullist indent outdent | emoticons charmap | removeformat | downloadPdf',
            tinycomments_mode: 'embedded',

            images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
                const xhr = new XMLHttpRequest();
                xhr.withCredentials = false;
                xhr.open('POST', 'upload.php');

                xhr.upload.onprogress = (e) => {
                    progress(e.loaded / e.total * 100);
                };

                xhr.onload = () => {
                    if (xhr.status === 403) {
                        reject({
                            message: 'HTTP Error: ' + xhr.status,
                            remove: true
                        });
                        return;
                    }

                    if (xhr.status < 200 || xhr.status >= 300) {
                        console.log(xhr);
                        reject('HTTP Error: ' + xhr.status + ' ' + xhr.statusText);
                        return;
                    }

                    const json = JSON.parse(xhr.responseText);

                    if (!json || typeof json.location != 'string') {
                        reject('Invalid JSON: ' + xhr.responseText);
                        return;
                    }

                    resolve(json.location);
                };

                xhr.onerror = () => {
                    reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
                };

                const formData = new FormData();
                formData.append('file', blobInfo.blob(), blobInfo.filename());

                xhr.send(formData);
            }),

            setup: function (editor) {

                              editor.on('init', function () {
editor.insertContent('<img src="/img/gtitop.png" alt="Votre image" style="max-width: 100%;">');
                });

                editor.ui.registry.addButton('downloadPdf', {
                    icon: 'export',
                    tooltip: 'Télécharger en PDF',
                    onAction: function () {
                        const content = tinymce.activeEditor.getContent();
                        const element = document.createElement('div');
                        element.innerHTML = content;

                        html2pdf().from(element).set({ 
                            margin: 1,
                            filename: 'document.pdf',
                            image: { type: 'jpeg', quality: 1 },
                            html2canvas: { scale: 2, logging: true },
                            jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
                        }).save();
                    }
                });
            }
        });
    </script>
{% endblock %}
Image

Image

Avatar du membre
Mammouth du PHP | 1564 Messages

25 mars 2024, 23:51

merci, ton site web c'est le dossier guide ? L'image 65fc22b686c9b.png existe-elle réellement dans le dossier ? Existe-t-il une règle de réécriture apache (htaccess) pour les images ?

Eléphant du PHP | 74 Messages

26 mars 2024, 00:14

Mon site web c'est le dossier "lewikidegti", guide est un controller et une page. Oui l'image existe bien, je peux la visualiser et l'ouvrir sans problème.

Alors pour la règle de réécriture apache htaccess j'en ai aucune idée... J'utilise Xampp et je travaille en local, je souhaite juste stocker mes images quelques parts et les appeler afin qu'il s'affiche, ça fonctionnait y'a quelques jours donc je ne connais pas la cause du problème malheureusement .... J'ai suivi les nombreuses docs

Je suis désolé, si je n'ai pas pu répondre à la dernière question

Avatar du membre
Mammouth du PHP | 1564 Messages

26 mars 2024, 00:45

Donc il cherche une image dans /lewikidegti/assets/images/.

Fais des liens vers tes images en absolut, soit avec l'adresse du site, soit en partant de la racine avec / devant le chemin.

Quand tu affiche l'image "assets/images/tonimage.png" sur ton site "http://localhost/lewikidegti" il va la chercher ici :
http://localhost/lewikidegti/assets/images/tonimage.png