28761
特定のhtmlタグと、その中の特定の属性のみ許可する正規表現を試行錯誤しています。

タグに関しては、

【方法１】

```

    preg_replace('/(?!<\/?(p|a|font)(>|\s[^>]*>))<("[^"]*"|\'[^\']*\'|[^\'">])*>/', '', $text);
    
```

【方法２】

```

    htmlescape($text, array('p', '/p', 'a', '/a', 'font', '/font'));
    
    function htmlescape($sValue, $arrAllowTag = array()) {
      $sValue = htmlspecialchars($sValue, ENT_QUOTES);
      if (count($arrAllowTag) == 0) return $sValue;
      foreach($arrAllowTag as $sTag) {
        if (strpos($sTag, '/') === false) {
          $sValue = preg_replace_callback("/&lt;\/?". $sTag . "( .*?&gt;|\/?&gt;)/i", "htmlescape_unhtmlescape", $sValue);
        }
      }
      return $sValue;
    }
    
    function htmlescape_unhtmlescape($sValue){
      $sString = $sValue[0];
      $sString = str_replace("&lt;", "<", $sString);
      $sString = str_replace("&gt;", ">", $sString);
      $sString = str_replace("&quot;", "\"", $sString);
      $sString = str_replace("&#039;", "'", $sString);
      return $sString;
    }
    
```

といった方法で可能なのですが、許可されたhtmlタグの中の、更に特定の属性のみ許可する場合の正規表現がうまくいきません。  
例えば

  * <font>タグであれば、「color」属性のみ許可したい
  * <p>タグであれば、「align」属性で、かつ値は「right」「left」「center」のみ許可したい

といった場合です。また、属性が現れる順番は保証されていません。

preg_replace_callbackなどを利用して効率の良い書き方があれば、ご教授いただければ幸いです。

タグを除くとき、削除するのかエスケープするのかは、どちらでも問題ありません。
CC BY-SA 3.0
2016-09-05T01:44:41.840
28686
2016-09-08T07:47:39.540
2016-09-05T02:37:14.303
8000
7352
question
php 正規表現
特定のhtmlタグと特定の属性を許可する正規表現
自己レスですが、【方法２】を弄って下記のように対応しました。  
かなり泥臭いですが、目的は達成できるように思います。

```

    $text = htmlescape($text, array('p', 'a', 'font', 'img'));
    
    function htmlescape($sValue, $arrAllowTag = array()) {
      $sValue = htmlspecialchars($sValue, ENT_QUOTES);
      if (count($arrAllowTag) == 0) return $sValue;
      foreach($arrAllowTag as $sTag) {
        if (strpos($sTag, '/') === false) {
          $sValue = preg_replace_callback(sprintf("/&lt;(%s)(?:(?:&gt;|\s(.+)?&gt;).+?&lt;\/%s&gt;|.+?\/>)/i", $sTag, $sTag), "htmlescape_unhtmlescape", $sValue);
        }
      }
      return $sValue;
    }
    
    function htmlescape_unhtmlescape($aValue){
      $sOrigString = $aValue[0];
      $sTag = $aValue[1];
      $sAttributes = $aValue[2];
    
      $sAttributes = str_replace(array('&quot;', '&#039;', '&lt;', '&gt;'), '', $sAttributes);
      $sAttributes = str_replace(array("\"", "'"), '', $sAttributes);
      $aParams = explode(' ', $sAttributes);
    
      $bError = false;
    
      switch($sTag) {
        case 'p':
          if(!$sAttributes) break;
          $aAlignParams = array('right', 'left', 'center');
          foreach($aParams as $sAttr) {
            list($sKey, $sVal) = explode('=', $sAttr);
            /*
              $sKeyと$sValの値をチェックして、意図しない値であれば
              $bError = true;
              break;
            */
          }
          break;
        case 'font':
        /*
          その他タグも同様にチェック
        */
      }
    
      if($bError === false) {
        $sOrigString = htmlspecialchars_decode($sOrigString);
      }
      return $sOrigString;
    }
    
```
CC BY-SA 3.0
2016-09-08T07:47:39.540
28761
2016-09-08T07:47:39.540
7352
28686
answer