简体   繁体   中英

Replace img to background-image div with php

Is there a way to replace img tag with div tag like below?

Original html:

<div class="article">
  <img src="/images/img-1.jpg" alt="alt for image">
</div>

Replaced html:

<div class="article">
 <div style="background: transparent url(/images/img-1.jpg) no-repeat;
 background-position: center center; background-size: cover; width: 566px; 
 height: 576px;">alt for image</div>
</div>

(Optional) Also is it possible to use the width and height from the parent div ie article class in my example instead of defining fixed width: 566px; height: 576px; width: 566px; height: 576px; ?

If it's possible, I want to use the str_replace function.

str_replace('?????', '?????', $article);

Edit:

There may be multiple elements with class article and there may be other elements inside article class div and from which I need to change img to div.

Edit2:

I was meaning as if I may have any content inside article div and just want to replace the img with div.

I may have:

<div class="article">
  <h1>heading</h1>
  <p>paragraph</p>
  <img src="/images/img-1.jpg" alt="alt for image">
</div>

Or I may have:

<div class="article">
  <h3>heading</h3>
  <p><img src="/images/img-1.jpg" alt="alt for image"> some paragraph </p>
</div>

So, I may have anything inside .article div and from which I wanted to replace img to div like

From:

<img src="/images/img-1.jpg" alt="alt for image" here-may-be-another-attribute-too>

To:

<div style="background: transparent url(/images/img-1.jpg) no-repeat;">alt for image</div>

use the php-class simplehtmldom ( http://simplehtmldom.sourceforge.net/ ) you can find and modify the HTML-Dom with CSS-like selectors.

<?php
require_once('simple_html_dom.php');

// Create DOM from string
$html = str_get_html('<div class="article">
  <img src="/images/img-1.jpg" alt="alt for image">
</div>');

$html->find('div.article', 0)->innertext = '<div style="background: transparent url(/images/img-1.jpg) no-repeat;
 background-position: center center; background-size: cover; width: 566px; 
 height: 576px;">alt for image</div>';

/** 
 * Output: <div id="article"><div style="background: transparent url(/images/img-1.jpg) no-repeat;
 * background-position: center center; background-size: cover; width: 566px; 
 * height: 576px;">alt for image</div></div>
 */
echo $html; 
?>

You can use PHP's native DOM library to found and replace html. I wrote some example, you adapt for your case. Hope help.

Updated code:

$html_str = '<div class="article newclass" id="some_id">
  <h1>heading</h1>
  <p>paragraph</p>
  <img src="images/image.png" alt="alt for image">
  <br>
  <h3>
  <p>paragraph</p>
    <img src="images/image2.png" alt="alt for image3">
  </h3>
  </div>';

$dom = new DOMDocument();
$dom->loadHTML($html_str);
$xpath = new DOMXpath($dom);

foreach ($xpath->query('//div[contains(@class, "article")]//img') as $img) {

  $new_img = replace($img, $width = '566', $height = '576');

  $replacement = $dom->createDocumentFragment();
  $replacement->appendXML($new_img);

  $img->parentNode->replaceChild($replacement, $img);

}

$new_html = $dom->saveXml();
echo $new_html;

function replace($img, $width, $height) {

  $href = $img->getAttribute('src');
  $alt = $img->getAttribute('alt');

  $new_img = '<div style="background: transparent url('.$href.') no-repeat;
    background-position: center center; background-size: cover; width: '.$width.'px;
    height: '.$height.'px;">'.$alt.'</div>';

  return $new_img;
}

replace function stay the same only change part where manage with DOM

Here you go. A tested and working solution. The error reporting is there in case PHP throws any errors. The child div also inherits the width and height of the parent div.

<?php

error_reporting(E_ALL);

ini_set("log_errors", 1);

/**
 * Display of all other errors
 */
ini_set("display_errors", 1);

/**
 * Display of all startup errors
 */
ini_set("display_startup_errors", 1);

$content = '
<div class="article">
  <h1>heading</h1>
  <p>paragraph</p>
  <img src="/images/img-1.jpg" alt="alt for image">
</div>
';

$domDocument = new DOMDocument();
$domDocument->loadHTML($content);
$domElemsToRemove = [];

$domXpath = new DOMXpath($domDocument);
$nodes = $domXpath->query('//div[@class="article"]/img');


$newNode ="<div style='background: transparent url(/images/img-1.jpg) no-repeat; width: inherit; height: inherit; background-position: center center; background-size: cover; width: 566px; height: 576px;'>alt for new image</div>";
$newDom = $domDocument->createDocumentFragment();
$newDom->appendXML($newNode);


foreach ($nodes as $node) {
    $node->parentNode->appendChild($newDom);
    $node->parentNode->removeChild($node);
}

echo $domDocument->saveHTML();
?>

Is there a way to replace img tag with div tag like below?

YES

a). DOM (prefered way)

b). REGEX

both methods are already implemented in other answers, use one you like

Note: if the html is generated dynamically by php, i would advise you to extract alt and src attributes value with preg_match_all regex here and then create a string from that, that would give you more flexibility, for eg:

$str ='<div class="article"><img src="/images/img-1.jpg" alt="alt for image"></div>';

preg_match_all('`src=(?:[\'"])(.*)[\'"].*alt=(?:[\'"])(.*)[\'"].*`U', $str, $matches);

$desiredHTML = <<<HTML
<div class="article">
 <div style="background: transparent url({$matches[1][0]}) no-repeat;
 background-position: center center; background-size: cover; width: 566px; 
 height: 576px;">{$matches[2][0]}</div>
</div>
HTML;

is it possible to use the width and height from the parent div?

YES by using following js code you can do that, since you can't find out the height of article div without rendering, and you want them in pixels, you have to use javascript

var cl = document.getElementsByClassName('article');
    for (var i = 0; i <= cl.length; i++)
    {
        var width = cl[i].style.width;
        var height = cl[i].style.height;
        cl[i].firstElementChild.style.width = width;
        cl[i].firstElementChild.style.height = height;
    };

If it's possible, I want to use the str_replace function?

NO , it's not possible with str_replace function.

  1. To do that you need to work with the preg_match function
  2. Try to set height and width as "inherit"

For your Problem try this:

$string = ' <div class="article">
                <img src="/images/img-1.jpg" alt="alt for image">
            </div>';
preg_match('@<div class="article">(.*?)</div>@is', $string, $replace);
preg_match('/<img src="(.*?)" alt="(.*?)">/', $string, $matches);

$string = str_replace($replace[1], '<div style="background: transparent url('.$matches[1].') no-repeat; background-position: center center; background-size: cover; width: inherit; height: inherit;">'.$matches[2].'</div>', $string);

To go from the old html to the new html we need to know two things:

  1. the src attribute
  2. the alt attribute

Once we know these two values we can easily create the new html format. I do that as follows:

<?php
$orig_html = <<<HERE
<div class="article">
  <img src="http://lorempixel.com/400/200" alt="alt for image">
</div>
HERE;

echo new_html($orig_html);

/* helper function to get the value of an attribute:
$attribute: the attribute you want to check (e.g. src)
$source: The html you want it to parse */
function get_attribute($attribute, $source) {
    $query  = '/' . $attribute . '="([^"]*)"/i';
    $result = array();
    preg_match($query, $source, $result);
    return $result[1];
}

/* helper function to return new html from the old html
$source: the old html */
function new_html($source) {
    $src = get_attribute('src', $source);
    $alt = get_attribute('alt', $source);

    return <<<HERE
 <div class="article">
   <div style="background: transparent url($src) no-repeat;
   background-position: center center; background-size: cover;">$alt</div>
  </div>
HERE;
}
?>

We can't use php to read the width and height of the parent (the article class), unless the width and height is defined in the markup. From your example it doesn't seem like these values are in the markup, so I'm assuming these dimensions are provided by css?

Instead you can always style the image with the following css: .article > div {width: 100%; height: 100%;} .article > div {width: 100%; height: 100%;} .

You can try something like this:

$content = "this is something with an <img src=\"test.png\"/> in it.";
$replaceWith = '<div style="background:url($1)"></div>';
$content = preg_replace('/<img\s+src="([^"]+)"[^>]+>/i', $replaceWith, $content); 
echo $content;

Change $replaceWith according to your markup.

YES.

But str_replace can not do this alone.

$article =<<<'EOT'
  <div class="article">
    <img src="/images/img-1.jpg" alt="alt for image">
  </div>
EOT;

// img -> div
$res = str_replace('<img', '<div', $article);
// src -> style
$res = preg_replace('/src="([^"]+)"/i', 'style="background: transparent url($1) no-repeat; background-position: center center; background-size: cover; width: 566px; height: 576px;"', $res);
// alt -> innerHTML
$res = preg_replace('/ alt="(.*)">/i', '>$1</div>', $res);
echo $res;

using preg_replace :

//your html code in a variable
$source = '<div class="article">
  <img src="/images/img-1.jpg" alt="alt for image1">
</div>
<div class="article">
  <img src="/images/img-5.jpg" alt="alt for image5">
</div>';

//class
class PregReplace{
    private static $instance;
    private $source;
    public $css = array('width'=>'600','height'=>'800','background-size'=>'cover','background-position'=>'center center','background'=>'transparent url($1) no-repeat');
    private $replace;
    private $result;
    private $pattern = '/\<div\s?class="article">\n?\r?\n?.*img\s?src="(.*?)"\salt="(.*?)".*\n?\r?\n?\<\/div\>/m';
    public function __construct(){

    }

    public function loadreplace(){
        $this->replace='<div class="article">
     <div style="background:'.$this->css['background'].'; background-position:'.$this->css['background-position'].'; background-size:'.$this->css['background-size'].'; width:'.$this->css['width'].'px; 
     height: '.$this->css['height'].'px;">$2</div>
    </div>';
    }

    public function setcss($array){
        $this->css = $array;
    }
    public function setsource($value){
        $this->source = $value;
        return $this;
    }
    public function setreplace($value){
        $this->replace = $value;
    }
    public function replacing(){
        $this->loadreplace();
        $this->result = preg_replace($this->pattern,$this->replace,$this->source);
        return $this;
    }
    public function result(){
        return $this->result;
    }
}

//process with preg_replace
$result = new PregReplace();
//you can set your css
$result->css['width'] = '566';
$result->css['height'] = '576';
//
var_dump($result->setsource($source)->replacing()->result());

Here is my approach, call normal Java Script from php:

<div class="article">
    <img src="../images/img-1.jpg" alt="alt for image">
</div>

<?php
$removeOldContent = '<script>document.getElementsByClassName("article")[0].remove();</script>';
$newContent = '<div class="article"><div style="background: transparent url(../images/img-1.jpg) no-repeat;
 background-position: center center; background-size: cover; width: 566px;
 height: 576px;">alt for image</div></div>';

$content = $removeOldContent . $newContent;

// this could be you replacing condition
// false will keep old content
// true will remove old content and view new content
if (false)
    echo $content;

You could read the file into a string, replace to your needs, then write back to either a new file or overwrite the original. Anyway, I'd probably just add a class for the div. Inline css is a pain.

You can use replaceWith method :

The .replaceWith() method, like most jQuery methods, returns the jQuery object so that other methods can be chained onto it. However, it must be noted that the original jQuery object is returned. This object refers to the element that has been removed from the DOM, not the new element that has replaced it.

The .replaceWith() method removes all data and event handlers associated with the removed nodes.

$('.article img').replaceWith(function(i, v){
    return $('<div/>', {
        style: 'background-image: url('+this.src+')',
        html: '<div style="background: transparent url(/images/img-1.jpg)no-repeat;background-position: center center; background-size: cover; width: 566px; height: 576px;">alt for image</div>'
    })
})

OR

echo "$('.article img').replaceWith(function(i, v){
            return $('<div/>', {
                style: 'background-image: url('+this.src+')',
                html: '<div style=\"background: transparent url(/images/img-1.jpg)no-repeat;background-position: center center; background-size: cover; width: 566px; height: 576px;\">alt for image</div>'
            })
        })";

Here is my jsFiddle.

This will accomplish what you are trying to do. Hope this helps.

$prev_str = '<div class="article"><img src="pics/flower.jpg" alt="alt for image"></div>';
preg_match('/'.preg_quote("<div class=\"").'(.*?)'.preg_quote("\"><img").'/is', $prev_str, $class);
$class_name=$class[1];//article
preg_match('/'.preg_quote("<img src=\"").'(.*?)'.preg_quote("\" alt=\"").'/is', $prev_str, $image);
$image_path=$image[1];//pics/flower.jpg
preg_match('/'.preg_quote("alt=\"").'(.*?)'.preg_quote("\"><").'/is', $prev_str, $alt);
$alt=$alt[1];//alt for image
//size that we are going to use in the div as well image div
$width="200px";
$height="200px";
echo '
<style>
div.article{
    min-height:'.$height.';
    width:'.$width.';
}
</style>';
/** additional hints in css formatting
div.article div{
    //display: inline-block;
    //width:inherit;
    //height:inherit;
    //width:100%;
    //height:100%;
}
**/
echo '<div class="'.$class_name.'">';
echo '<div style="background: transparent url('.$image_path.') no-repeat;
 background-position: center center; background-size: cover;width:'.$height.'; 
 height: '.$width.';">'.$alt.'</div>
</div>';

This method is almost entirely preg_replace ; it does have a few nice additions:

  1. The CSS values wxh are added as part of the replacement.
  2. All of the other main values ( class , href , and alt ) are dynamically replaced.

It basically uses two patterns, the first parses the CSS and the second replaces the <div> .

Code :

<?php

$str = '<div class="article"><img src="/images/image.png" alt="alt for image"></div>';
$css = '<style> .article { font-size:16px; font-weight:bold; width:566px; height:576px; } </style>
';

function replace($str, $css) {

    preg_match( '@>\s\.(.+)\s{\s(.*)\s}@', $css, $res);

        $style['class'] = $res[1];
        $attrs = explode("; ", $res[2]);

        foreach ($attrs as $attr) {
                if (strlen(trim($attr)) > 0) {
                $kv = explode(":", trim($attr));
                $style[trim($kv[0])] = trim($kv[1]);
            }
        }

$rep = '<div class="$1">
 <div style="background: transparent url($2) no-repeat; 
 background-position: center center; background-size: cover; width: '.$style['width'].';
 height: '.$style['height'].'">$3</div>
</div>
';

    return preg_replace( '@.+class="(.+)"><.*="(.+)"\\salt="(.+)".+@', $rep, $str );
}
    $str = replace($str, $css);
?>

<html>
<head>
<?php echo $css; ?>
</head>
<body>
<?php echo $str; ?>
</body>
</html>

Example :

http://ideone.com/TJHR1b

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM