Skip to content

Instantly share code, notes, and snippets.

@JamshidbekAkhlidinov
Last active June 18, 2025 12:48
Show Gist options
  • Select an option

  • Save JamshidbekAkhlidinov/13ac7dc258f6386575b2ae83aecbcfb0 to your computer and use it in GitHub Desktop.

Select an option

Save JamshidbekAkhlidinov/13ac7dc258f6386575b2ae83aecbcfb0 to your computer and use it in GitHub Desktop.

Revisions

  1. JamshidbekAkhlidinov renamed this gist Jun 18, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. JamshidbekAkhlidinov renamed this gist Jun 18, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. JamshidbekAkhlidinov created this gist Jun 18, 2025.
    107 changes: 107 additions & 0 deletions TestController.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    <?php
    /*
    * Jamshidbek Akhlidinov
    * 18 - 6 2025 16:42:43
    * https://ustadev.uz
    * https://github.com/JamshidbekAkhlidinov
    */

    namespace app\modules\admin\controllers;

    use DOMDocument;
    use Yii;
    use yii\web\Controller;
    use yii\web\Response;

    class TestController extends Controller
    {
    public function actionIndex()
    {
    return $this->render('form');
    }


    public function actionConvertImages()
    {
    Yii::$app->response->format = Response::FORMAT_JSON;
    $html = Yii::$app->request->post('html');

    if (empty($html)) {
    return ['success' => false, 'error' => 'HTML not provided'];
    }

    $cleanHtml = $this->convertImagesToLocalWebp($html);
    return ['success' => true, 'html' => $cleanHtml];
    }

    private function convertImagesToLocalWebp($htmlContent)
    {
    libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $dom->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'));

    $images = $dom->getElementsByTagName('img');
    foreach ($images as $img) {
    $src = $img->getAttribute('src');

    if (filter_var($src, FILTER_VALIDATE_URL)) {

    $imgData = @file_get_contents($src);
    if ($imgData === false) continue;

    // Rasm nomi va serverga saqlash yo‘li
    $fileName = 'img_' . uniqid() . '.webp';
    $savePath = Yii::getAlias('@webroot/uploads/' . $fileName);
    $webPath = Yii::getAlias('@web/uploads/' . $fileName);

    $tmpPath = sys_get_temp_dir() . '/' . uniqid() . '.img';
    file_put_contents($tmpPath, $imgData);

    $mime = mime_content_type($tmpPath);
    switch ($mime) {
    case 'image/jpeg':
    case 'image/pjpeg':
    $imgRes = imagecreatefromjpeg($tmpPath);
    break;

    case 'image/png':
    $imgRes = imagecreatefrompng($tmpPath);
    break;

    case 'image/gif':
    $imgRes = imagecreatefromgif($tmpPath);
    break;

    case 'image/bmp':
    case 'image/x-ms-bmp':
    if (function_exists('imagecreatefrombmp')) {
    $imgRes = imagecreatefrombmp($tmpPath);
    } else {
    continue 2;
    }
    break;

    case 'image/webp':
    if (function_exists('imagecreatefromwebp')) {
    $imgRes = imagecreatefromwebp($tmpPath);
    } else {
    continue 2;
    }
    break;
    default:
    continue 2;
    }

    // webp saqlash
    imagewebp($imgRes, $savePath, 80);
    imagedestroy($imgRes);

    $img->setAttribute('src', $webPath);
    $img->setAttribute('width', '500');
    }
    }

    // Qayta string holatga qaytarish
    return $dom->saveHTML($dom->getElementsByTagName('body')->item(0));
    }
    }
    123 changes: 123 additions & 0 deletions form,php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,123 @@
    <?php
    /*
    * Jamshidbek Akhlidinov
    * 18 - 6 2025 16:42:58
    * https://ustadev.uz
    * https://github.com/JamshidbekAkhlidinov
    */

    use dosamigos\tinymce\TinyMce;

    echo TinyMce::widget([
    'name' => 'test',
    'options' => ['rows' => 10],
    'language' => 'en',
    'clientOptions' => [
    'height' => '80vh',
    'plugins' => [
    "code",
    "lists link image preview",
    'code', 'preview', 'image', 'media', 'link',
    'table', 'lists', 'fullscreen', 'wordcount'
    ],
    'toolbar' => 'undo redo | bold italic | alignleft aligncenter alignright | clearhtml | optimizeimages | code',
    'setup' => new \yii\web\JsExpression(<<<JS
    function (editor) {
    // Clear HTML tugmasi
    editor.ui.registry.addButton('clearhtml', {
    text: 'Clear HTML',
    icon: 'remove-format',
    tooltip: 'Remove attributes from all tags except src in img, video, iframe',
    onAction: function () {
    let content = editor.getContent();
    let div = document.createElement('div');
    div.innerHTML = content;

    function cleanAttributes(el) {
    if (el.nodeType === 1) {
    let tag = el.tagName.toLowerCase();
    let keepSrc = ['img', 'iframe', 'video'].includes(tag);

    let attrs = Array.from(el.attributes);
    for (let attr of attrs) {
    if (keepSrc && attr.name === 'src') {
    continue; // src ni saqlab qolamiz
    }
    el.removeAttribute(attr.name);
    }
    if (tag === 'img') {
    el.setAttribute('width', '500');
    }

    for (let i = 0; i < el.childNodes.length; i++) {
    cleanAttributes(el.childNodes[i]);
    }
    }
    }
    cleanAttributes(div);
    editor.setContent(div.innerHTML);
    }
    });

    // Optimize Images tugmasi
    editor.ui.registry.addButton('optimizeimages', {
    text: 'Optimize Images',
    icon: 'refresh',
    tooltip: 'Download and convert all external images to webp',
    onAction: function () {
    const content = editor.getContent();
    let progressSpan = document.getElementById('image-optimize-progress');
    if (!progressSpan) {
    progressSpan = document.createElement('span');
    progressSpan.id = 'image-optimize-progress';
    progressSpan.style.marginLeft = '10px';
    progressSpan.style.fontWeight = 'bold';
    editor.getContainer().parentNode.insertBefore(progressSpan, editor.getContainer());
    }

    let percent = 1;
    progressSpan.textContent = 'Processing: 1%';

    const interval = setInterval(() => {
    if (percent < 95) {
    percent++;
    progressSpan.textContent = 'Processing: ' + percent + '%';
    }
    }, 150);

    $.ajax({
    url: '/admin/test/convert-images',
    method: 'POST',
    data: {
    html: content,
    name: 'ustadev'
    },
    headers: {
    'X-CSRF-Token': yii.getCsrfToken()
    },
    success: function (data) {
    clearInterval(interval);
    progressSpan.textContent = 'Done ✅';

    if (data.success && data.html) {
    editor.setContent(data.html);
    } else {
    alert('Xatolik: ' + (data.error || 'HTML topilmadi'));
    }
    },
    error: function (xhr, status, error) {
    clearInterval(interval);
    progressSpan.textContent = 'Xato ❌';
    console.error('API error:', error);
    }
    });

    }
    });
    }
    JS
    ),
    ]
    ]);