これは preg_replace_callback を使えば簡単にできるだろうと考え始めましたが、ちょっとした怪物になってしまいました。少しのリファクタリングで簡単に改善できると確信しています:
<?php
// Some HTML test data with two images. For one image I've thrown in some extra styles, just
// to complicate things
$content= '<img alt="image-alt-2" src="image-path" style="width: 20px; height: 15px; border: 1px solid red;" title="image-title" />
<p>Some other tags. These shouldn\'t be changed<br />Etc.</p>
<img alt="image-alt-2" src="image-path-2" style="width: 35px; height: 30px;" title="another-image-title" />
<p>This last image only has a width and no height</p>
<img alt="image-alt-3" src="image-path-3" style="width:35px;" title="another-image-title" />';
$content= preg_replace_callback('/<img ((?:[a-z]+="[^"]*"\s*)+)\/>/i', 'replaceWidthHeight', $content);
var_dump($content);
function replaceWidthHeight($matches) {
// matches[0] will contain all the image attributes, need to split
// those out so we can loop through them
$submatches= array();
$count= preg_match_all('/\s*([a-z]+)="([^"]*)"/i', $matches[1], $submatches, PREG_SET_ORDER);
$result= '<img ';
for($ndx=0;$ndx<sizeof($submatches);$ndx++) {
if ($submatches[$ndx][1]=='style') {
// Found the style tag ...
$width= ''; // Temporary storage for width and height if we find them
$height= '';
$result.= ' style="';
$styles= split(';', $submatches[$ndx][2]);
foreach($styles as $style) {
$style= trim($style); // remove unwanted spaces
if (strlen($style)>6 && substr($style, 0, 6)=='width:') {
$width= trim(substr($style, 6));
}
elseif (strlen($style)>7 && substr($style, 0, 7)=='height:') {
$height= trim(substr($style, 7));
}
else { // Some other style - pass it through
$result.= $style;
}
}
$result.= '"';
if (!empty($width)) $result.= " width=\"$width\"";
if (!empty($height)) $result.= " height=\"$height\"";
}
else {
// Something else, just pass it through
$result.= $submatches[$ndx][0];
}
}
return $result.'/>';
}