lamefun
lamefun

Reputation: 4232

How to implement a printf-like function in PHP?

I want to make a db_queryf function for my database abstraction. It will work somewhat like sqlite3_mprintf from SQLite: db_queryf('select * from pages where name=%q', $_GET['name']), where %q will produce a properly escaped string. What is the proper way of making printf-like functions in PHP? Is there any helper functions for that or I should parse it myself?

Upvotes: 0

Views: 704

Answers (4)

Andreas Grapentin
Andreas Grapentin

Reputation: 5796

okay, since I had exactly the same problem, I gave it a shot, and it seems to work quite nicely.

The following function sits inside a database wrapping class, and expects to be called like printf, where %% is transformed to a literal %, %e marks a string argument to be escaped, and %u marks a string argument to taken as-is.

LOGDB is a second database wrapping class, that is responsible for catching and logging all kinds of errors.

  public static function query($format)
  {
    $query = $format . ' ';

    $argc = func_num_args();
    $argv = func_get_args();

    $index_query = 0;
    $index_args = 1;

    while (($index_query = strpos($query, '%', $index_query)) !== false)
      {
        switch ($query[$index_query + 1])
          {
          case '%':
            $query = substr_replace($query, '', $index_query, 1);
            $index_query++;
            break;
          case 'e':
            if ($index_args >= $argc)
              {
                LOG::failedQuery($format, "not enough arguments for format");
                return false;
              }
            $query = substr_replace($query, DB::escape($argv[$index_args]), $index_query, 2);
            $index_query += strlen($argv[$index_args]);
            $index_args++;
            break;
          case 'u':
            if ($index_args >= $argc)
              {
                LOG::failedQuery($format, "not enough arguments for format");
                return false;
              }
            $query = substr_replace($query, $argv[$index_args], $index_query, 2);
            $index_query += strlen($argv[$index_args]);
            $index_args++;
            break;
          default:
            LOG::failedQuery($format, "unknown control sequence '%" . $query[$index_query + 1] . "'");
            return false;
          }
      }

    if ($index_args != $argc)
      {
        LOG::failedQuery($format, "too many arguments for format");
        return false;
      }

    $res = mysqli_query(self::$handle, $query);
    if (!$res)
      LOGDB::failedQuery($query, mysqli_error(self::$handle));

    return $res;
  }

Note: the code is mostly untested, chances are, it contains a bunch of bugs. use with caution :)

Upvotes: 0

Brad Koch
Brad Koch

Reputation: 20267

Use PDO prepared statements. Replacing into the string isn't good enough, you should be sanitizing.

Upvotes: 1

Wrikken
Wrikken

Reputation: 70460

I am confused... (s)printf plainly allready exists, and you probably want to use SQLite3Stmt::bindValue more for this, unless you want to end up in escaping / sql-injection hell..

Upvotes: 2

KingCrunch
KingCrunch

Reputation: 131871

sprintf()

sprintf('select * from pages where name=\'%s\'', $_GET['name']);

Its very important, that you sanitize everything in $_GET, before you use it!

Upvotes: 0

Related Questions