Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Baumgard committed Feb 10, 2017
0 parents commit 6289446
Show file tree
Hide file tree
Showing 7 changed files with 721 additions and 0 deletions.
339 changes: 339 additions & 0 deletions GPL.txt

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2008, 2011, 2015-2017 Tim Baumgard

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http:https://www.gnu.org/licenses/>.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# PHP PCRE Tester

PHP PCRE Tester is a simple development tool that makes it easy to test Perl-compatible regular expressions as used in PHP. Open it up in your browser, give it a regex pattern, an optional replacement value, and a subject, and it gives you the result with the matched portions of the subject highlighted and optionally replaced.

It requires a web server, PHP 7, and a browser.

## Screenshot

[![](screenshot-small.png "Usage Example")](screenshot.png)

## License

&copy; 2008, 2011, 2015-2017 Tim Baumgard. This tool is licensed under [GPL v3.0](https://www.gnu.org/licenses/gpl-3.0-standalone.html).
207 changes: 207 additions & 0 deletions index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?php

/**
* Tool to test Perl-compatible regular expressions (PCRE) in PHP.
*
* Copyright 2008, 2011, 2015-2017 Tim Baumgard
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http:https://www.gnu.org/licenses/>.
*/

// -----------------------------------------------------------------------------
// Defaults
//

$delimiter = "/";

$modifiers = [
"caseless" => [
"label" => "Treat pattern case-insensitively",
"modifier" => "i",
"selected" => false],
"multiline" => [
"label" => "Enable multi-line mode for anchoring meta-characters",
"modifier" => "m",
"selected" => false],
"dotall" => [
"label" => "Include newlines in dot meta-character",
"modifier" => "s",
"selected" => false],
"extended" => [
"label" => "Enable extended mode for white space",
"modifier" => "x",
"selected" => false],
"anchored" => [
"label" => "Anchor pattern to start of subject",
"modifier" => "A",
"selected" => false],
"dollarEndonly" => [
"label" => "Anchor pattern to end of subject",
"modifier" => "D",
"selected" => false],
"ungreedy" => [
"label" => "Invert greediness of quantifiers",
"modifier" => "U",
"selected" => false],
"extra" => [
"label" => "Treat unnecessary escaping as error",
"modifier" => "X",
"selected" => false],
"infoJchanged" => [
"label" => "Allow duplicate names for subpatterns",
"modifier" => "J",
"selected" => false],
"utf8" => [
"label" => "Treat strings as UTF-8",
"modifier" => "u",
"selected" => false]];

// -----------------------------------------------------------------------------
// Main
//

$result = null;
$errorMessage = null;

$pattern = $_POST["pattern"] ?? "";
$replacement = $_POST["replacement"] ?? "";
$subject = $_POST["subject"] ?? "";
$action = $_POST["action"] ?? "";
$delimiter = $_POST["delimiter"] ?? $delimiter;

if ($action == "submit") {
$modifierString = "";

foreach ($modifiers as $id => $modifier) {
if (($_POST[$id] ?? "") == "on") {
$modifiers[$id]["selected"] = true;
$modifierString .= $modifier["modifier"];
} else {
$modifiers[$id]["selected"] = false;
}
}

$isDelimiterValid = @preg_match($delimiter.$delimiter, "") !== false;

if (!$isDelimiterValid) {
$errorMessage = "The delimiter is invalid.";
} else {
$fullPattern = $delimiter . $pattern . $delimiter . $modifierString;
$marker = bin2hex(random_bytes(16));

$callback = function($matches) use ($fullPattern, $replacement, $marker) {
if (strlen($replacement) > 0) {
$result = preg_replace($fullPattern, $replacement, $matches[0]);
} else {
$result = $matches[0];
}

return $marker . $result . $marker;
};

$result = @preg_replace_callback($fullPattern, $callback, $subject);

if ($result === null) {
$errorMessage = "The pattern is invalid.";
} else {
// Escape the result now since HTML will be added in the following step.
$result = htmlspecialchars($result);

// Replace the expression markers with semantic HTML markers.
$htmlPattern = "/{$marker}(.*?){$marker}/ms";
$htmlReplacement = "<mark>\\1</mark>";
$result = preg_replace($htmlPattern, $htmlReplacement, $result);
}
}
} else if ($action == "clear") {
$pattern = "";
$replacement = "";
$subject = "";
}

?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>PHP PCRE Tester</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<header id="header">
<h1>PHP PCRE Tester</h1>
</header>

<?php if (isset($errorMessage)) { ?>
<section id="error">
<p role="alert"><b>Error</b>: <?= htmlspecialchars($errorMessage) ?></p>
</section>
<?php } ?>

<main id="content">
<header>
<nav class="documentation">
<ul>
<li><a href="https://secure.php.net/manual/en/book.pcre.php">PHP PCRE Documentation</a></li>
<li><a href="http:https://pcre.org/current/doc/html/">PCRE2 Documentation</a></li>
</ul>
</nav>
</header>

<?php if (isset($result)) { ?>
<pre class="result"><?= $result ?></pre>
<hr />
<?php } ?>

<form method="post">
<fieldset class="regex">
<label for="pattern">Pattern</label>
<textarea id="pattern" name="pattern" placeholder="\b\w+\b"><?= htmlspecialchars($pattern) ?></textarea>

<label for="replacement">Replacement</label>
<textarea id="replacement" name="replacement" placeholder="[\0]"><?= htmlspecialchars($replacement) ?></textarea>

<label for="subject">Subject</label>
<textarea id="subject" name="subject" placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit."><?= htmlspecialchars($subject) ?></textarea>

<label for="delimiter">Delimiter</label>
<input type="text" id="delimiter" name="delimiter" size="1" maxlength="1" required="required" value="<?= htmlspecialchars($delimiter) ?>" />
</fieldset>

<fieldset class="modifiers">
<legend>Pattern Modifiers</legend>

<?php foreach ($modifiers as $id => $modifier) { ?>
<span class="modifier">
<input type="checkbox" id="<?= htmlspecialchars($id) ?>" name="<?= htmlspecialchars($id) ?>" <?php if ($modifier["selected"]) print 'checked="checked"'; ?> />
<label for="<?= htmlspecialchars($id) ?>">
(<code><?= htmlspecialchars($modifier["modifier"]) ?></code>)
<?= htmlspecialchars($modifier["label"]) ?>
</label>
</span>
<?php } ?>
</fieldset>

<fieldset class="actions">
<button type="submit" name="action" value="submit">Submit</button>
<button type="reset">Reset</button>
<button type="submit" name="action" value="clear">Clear</button>
</fieldset>
</form>
</main>

<footer id="footer">
<p>&copy; 2008, 2011, 2015-2017 Tim Baumgard</p>
</footer>
</body>
</html>
Binary file added screenshot-small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
149 changes: 149 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/******************************************************************************/
/* Built-in Elements */
/******************************************************************************/

* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: monospace;
font-size: 1em;
}

html, body {
min-width: 200px;
}

h1 {
font-size: 2em;
}

fieldset {
position: relative;
border: none;
}

legend {
margin-bottom: 8px;
font-weight: bold;
}

legend::after {
content: ":";
}

input[type="text"] {
padding: 4px;
border: 1px solid #737373;
}

button {
padding: 8px 16px;
}

textarea {
width: 100%;
height: 100px;
padding: 4px;
}

/******************************************************************************/
/* Page Sections */
/******************************************************************************/

#header {
padding: 32px;
text-align: center;
}

#error {
margin-bottom: 16px;
padding: 4px;
text-align: center;
color: #eb400c;
}

#content {
padding: 16px;
border-top: 1px solid #000000;
border-bottom: 1px solid #000000;
background-color: #dddddd;
}

#footer {
padding: 16px;
text-align: center;
}

/******************************************************************************/
/* Content Sections */
/******************************************************************************/

.result, .regex, .modifiers {
margin-top: 24px;
margin-bottom: 24px;
}

.documentation li {
display: inline-block;
margin-right: 24px;
}

.result {
padding: 16px;
border: 1px solid #737373;
background-color: #ffffff;
white-space: pre-wrap;
word-wrap: break-word;
}

.result mark {
background-color: #f9d3d3;
}

.regex label {
display: block;
margin-bottom: 2px;
font-weight: bold;
}

.regex label::after {
content: ":";
}

.regex textarea + label, .regex input + label {
margin-top: 8px;
}

.modifiers .modifier {
display: block;
margin-bottom: 4px;
}

.modifiers .modifier input[type="checkbox"] {
float: left;
}

.modifiers .modifier label {
display: block;
margin-left: 24px;
}

.actions button {
width: 100%;
}

.actions button + button {
margin-top: 12px;
}

@media (min-width: 481px) {
.actions button {
width: auto;
margin-right: 12px;
}

.actions button + button {
margin-top: 0;
}
}

0 comments on commit 6289446

Please sign in to comment.