SVG and PHP

From Svg wiki

Using PHP to create dynamic SVG isn't that hard. There are just some basics you have to know.


Contents

inline vs. embedded

  • Inline: Writing the SVG directly inside a xhtml file.
  • Embedded: Using a second PHP file to create just the SVG and embedded this with the object tag into the html file.

Poorly the inline SVG need a lot of cross browser testing.

For the Quick start a separate PHP file is used for not having to deal with a xhtml file, but i actually prefer the inline version.

Quick start

time to start. for now we are creating a simple delete icon.

Making a PHP file a SVG

2 lines are needed to make the PHP output SVG, the Rest is just the content of the SVG:

delete.php

<?php
  header('Content-Type: image/svg+xml');
  echo '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
?>
<svg width="32px" height="32px" viewBox="0 0 100 100" version="1.0" xmlns="http://www.w3.org/2000/svg">
  <rect width="100" height="100" fill="lightgray" />
  <g stroke="red">
    <line x1="10" y1="10" x2="80" y2="80" stroke-width="10" />
    <line x1="10" y1="80" x2="80" y2="10" stroke-width="10" />
  </g>
</svg>
  • The first line is the SVG MimeType. This makes the Browser realizing that the file called .php is a SVG.
  • The second line had to be outputted with echo because '<?' is the short form of the php open tag '<?php'.

Dynamic Content

If anybody would now say that the priviose result would be much easier accived by just calling the file .svg i would have to agree.

But now the fun begins. Why creating multiple SVG's if they are all similar. lets adjust the foreground color (fg) the background color (bg) and the size dynamically.

delete.php

<?php
  header('Content-Type: image/svg+xml');
  echo '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
?>
<svg width="<?php echo $_GET['size']; ?>" height="<?php echo $_GET['size']; ?>" viewBox="0 0 100 100" version="1.0" xmlns="http://www.w3.org/2000/svg">
  <rect width="100" height="100" fill="<?php echo $_GET['bg']; ?>" />
  <g stroke="<?php echo $_GET['fg']; ?>">
    <line x1="10" y1="10" x2="80" y2="80" stroke-width="10" />
    <line x1="10" y1="80" x2="80" y2="10" stroke-width="10" />
  </g>
</svg>

if we now call this file with delete.php?size=32px&fg=red&bg=lightgray we get the exact same result, but try:

  • delete.php?size=32px&fg=lightgray&bg=red
  • delete.php?size=2cm&fg=black&bg=lightgray
  • delete.php?size=50%25&fg=%23CCCCFF&bg=%23FFF (%25 is '%' and %23 is '#')
  • delete.php?size=1024px&fg=red&bg=green (be carefull)

Embedding it in a xhtml file

Main Article: SVG and HTML

Now that we have a dynamic graphic we wanna use it, of cause.

example.php:

<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div style="text-align:right;margin:4px;padding:4px;background-color:#EEEEEE">
      <a href="?action=delete">
        <object data="delete.php?fg=red&bg=lightgray&size=24px" type="image/svg+xml" width="32" height="32">
          x
        </object>
      </a>
    </div>
    <div style="text-align:right;margin:4px;padding:4px;background-color:lightblue">
      <a href="?action=delete">
        <object data="delete.php?fg=red&bg=blue&size=32px" type="image/svg+xml" width="32" height="32">
          x
        </object>
      </a>
    </div>
  </body>
</html>

the x inside the <object>-tag is just the alternative content for browsers that are not able to display SVG's.

inline

Main Article: Inline SVG

As i mentioned before would prefer inline SVG's, as only one php file is needed. But it's hard, if not impossible, to get it working cross browsers.

First we need to convert the delete.php into a function.

<?php
function deleteIcon($size=32,$fg='red',$bg='lightgray')
  {
    $svg = '<svg:svg width="'.$size.'px" height="'.$size.'" viewBox="0 0 100 100" version="1.0" xmlns="http://www.w3.org/2000/svg">';
    $svg.= '  <svg:rect width="100" height="100" fill="'.$bg.'" />';
    $svg.= '  <svg:g stroke="'.$fg.'">';
    $svg.= '    <svg:line x1="10" y1="10" x2="80" y2="80" stroke-width="10" />';
    $svg.= '    <svg:line x1="10" y1="80" x2="80" y2="10" stroke-width="10" />';
    $svg.= '  </svg:g>';
    $svg.= '</svg:svg>';
    return $svg;
  }
?>

The 'svg:' prefix is needed to use the ASV Hack.

Now we are able to call the function inside a .php file:

example.php

<?php
if(stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) header('Content-type: application/xhtml+xml');
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:svg="http://www.w3.org/2000/svg"
      xml:lang="en">
  <head>
    <title>Example (inline)</title>
    <object id="AdobeSVG" classid="clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2"></object>
    <?php echo'<?import namespace="svg" implementation="#AdobeSVG"?>' ?>
  </head>
  <body>
    <div style="text-align:right;margin:4px;padding:4px;background-color:#EEEEEE">
      <a href="?action=delete">
         <?php echo deleteIcon(24); ?>
      </a>
    </div>
    <div style="text-align:right;margin:4px;padding:4px;background-color:lightblue">
      <a href="?action=delete">
         <?php echo deleteIcon(32,'red','blue'); ?>
      </a>
    </div>
  </body>
</html>
<?php
function deleteIcon($size=32,$fg='red',$bg='lightgray')
  {
    $svg = '<svg:svg width="'.$size.'px" height="'.$size.'" viewBox="0 0 100 100" version="1.0" xmlns="http://www.w3.org/2000/svg">';
    $svg.= '  <svg:rect width="100" height="100" fill="'.$bg.'" />';
    $svg.= '  <svg:g stroke="'.$fg.'">';
    $svg.= '    <svg:line x1="10" y1="10" x2="80" y2="80" stroke-width="10" />';
    $svg.= '    <svg:line x1="10" y1="80" x2="80" y2="10" stroke-width="10" />';
    $svg.= '  </svg:g>';
    $svg.= '</svg:svg>';
    return $svg;
  }
?>

Useful examples

poker deck

<?php
header('Content-Type: image/svg+xml');
$n=$_GET['n'];

echo '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
echo '<svg height="193" id="svg2" version="1.0" width="143" x="0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0">';
echo '<symbol>';
echo '<path d="';
switch($_GET['s'])
{
 case 'c':
   echo 'M -1,1 L -4,12 L 4,12 L 1,1 C 3,1 7,7 9,7 C 15,7 15,-7 9,-7 C 7,-7 3,-1 1,-1 C 1,-4 5,-10 5,-13 C 5,-23 -5,-23 -5,-13 C -5,-10 -1,-4 -1,-1 C -3,-1 -7,-7 -9,-7 C -15,-7 -15,7 -9,7 C -7,7 -3,1 -1,1 z';
   $col='#000000';
   break;
 case 'h':
   echo 'M 0,-10 C 0,-25 14,-25 14,-10 C 14,-5 5,7 0,15 C -5,7 -14,-5 -14,-10 C -14,-25 0,-25 0,-10 z';
   $col='#FF0000';
   break;
 case 'd':
   echo 'M 0,20 C -1,15 -10,0 -14,0 C -10,0 -1,-15 0,-20 C 1,-15 10,0 14,0 C 10,0 1,15 0,20 z';
   $col='#FF0000';
   break;
 case 's':
   echo 'M -1,1 L -4,12 L 4,12 L 1,-1 C 1,5 14,10 14,0 C 14,-5 5,-17 0,-25 C -5,-17 -14,-5 -14,0 C -14,10 -1,5 -1,0 z';
   $col='#000000';
   break;
}
echo '" id="symbol" style="fill:'.$col.'"/>';

echo '<text x="0" y="0" id="num" text-anchor="middle" font-family="sans-serif" style="font-size:40px;font-weight:bold;fill:'.$col.';stroke:none">'.$_GET['n'].'</text>';
echo '</symbol>';

echo '<rect x="5" y="5" width="138" height="188" rx="16" ry="16" style="fill:#000000;fill-opacity:0.5"/>';
echo '<rect x="0" y="0" width="138" height="188" rx="16" ry="16" style="fill:#cccccc"/>';
echo '<rect x="2" y="2" width="138" height="188" rx="16" ry="16" style="fill:#cccccc"/>';
echo '<rect x="1" y="1" width="138" height="188" rx="16" ry="16" style="fill:#ffffff"/>';

echo '<use x="28" y="40" xlink:href="#num" transform="scale(.75,1)" />';
echo '<use x="28" y="40" xlink:href="#num" transform="rotate(180,70,95) scale(.75,1)" />';

echo '<use x="20" y="70" xlink:href="#symbol" />';
echo '<use x="20" y="70" xlink:href="#symbol" transform="rotate(180,70,95)" />';



if($n>=8) echo '<use x="100" y="100" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="180" y="100" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=4 && $n<=7) echo '<use x="100" y="110" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n==3) echo '<use x="140" y="110" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=4 && $n<=7) echo '<use x="180" y="110" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n==10|| $n==2) echo '<use x="140" y="125" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n==7) echo '<use x="140" y="140" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="100" y="170" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="180" y="170" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n==6) echo '<use x="100" y="190" transform="scale(0.5,0.5)" xlink:href="#symbol" />';

if($n %2) echo '<use x="140" y="190" transform="scale(0.5,0.5)" xlink:href="#symbol" />';
if($n=='J'||$n=='Q'||$n=='K') echo '<use x="47" y="60" xlink:href="#num" transform="scale(1.5,2)" />';
if($n=='A') echo '<use x="35" y="49" transform="scale(2,2)" xlink:href="#symbol" />';

if($n>=8) echo '<use x="100" y="100" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="180" y="100" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n>=4 && $n<=7) echo '<use x="100" y="110" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n==3) echo '<use x="140" y="110" transform="rotate(180,70,95) scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=4 && $n<=7) echo '<use x="180" y="110" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n==10|| $n==2) echo '<use x="140" y="125" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n==7) echo '<use x="140" y="140" transform="rotate(180,70,95) scale(0.5,0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="100" y="170" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n>=8) echo '<use x="180" y="170" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';
if($n==6) echo '<use x="100" y="190" transform="rotate(180,70,95) scale(0.5)" xlink:href="#symbol" />';

echo '</svg>';
?>