Skip to content

Instantly share code, notes, and snippets.

@fer-ri
Last active December 16, 2019 06:09
Show Gist options
  • Save fer-ri/8470520 to your computer and use it in GitHub Desktop.
Save fer-ri/8470520 to your computer and use it in GitHub Desktop.
PHP Spinner Updated – Spin articles for SEO Taken from http://www.paul-norman.co.uk/2010/09/php-spinner-updated-spin-articles-for-seo/ All credit goes to him
<?php
// Example 1
$string = '{{The|A}} {{quick|speedy|fast}} {{brown|black|red}} {{fox|wolf}} {{jumped|bounded|hopped|skipped}} over the {{lazy|tired}} {{dog|hound}}';
echo '<p>';
for($i = 1; $i <= 5; $i++)
{
echo Spinner::detect($string, false).'<br />';
// or Spinner::flat($string, false).'<br />';
}
echo '</p>';
// Example 2
$string = '{{A {{simple|basic}} example|An uncomplicated scenario|The {{simplest|trivial|fundamental|rudimentary}} case|My {{test|invest{{igative|igation}}}} case}} to illustrate the {{function|problem}}';
echo '<p>';
for($i = 1; $i <= 5; $i++)
{
echo Spinner::detect($string, false).'<br />';
// or Spinner::nested($string, false).'<br />';
}
echo '</p>';
<?php
class Spinner
{
# Detects whether to use the nested or flat version of the spinner (costs some speed)
public static function detect($text, $seedPageName = true, $openingConstruct = '{{', $closingConstruct = '}}', $separator = '|')
{
if(preg_match('~'.$openingConstruct.'(?:(?!'.$closingConstruct.').)*'.$openingConstruct.'~s', $text))
{
return self::nested($text, $seedPageName, $openingConstruct, $closingConstruct, $separator);
}
else
{
return self::flat($text, $seedPageName, false, $openingConstruct, $closingConstruct, $separator);
}
}
# The flat version does not allow nested spin blocks, but is much faster (~2x)
public static function flat($text, $seedPageName = true, $calculate = false, $openingConstruct = '{{', $closingConstruct = '}}', $separator = '|')
{
# Choose whether to return the string or the number of permutations
$return = 'text';
if($calculate)
{
$permutations = 1;
$return = 'permutations';
}
# If we have nothing to spin just exit (don't use a regexp)
if(strpos($text, $openingConstruct) === false)
{
return $$return;
}
if(preg_match_all('!'.$openingConstruct.'(.*?)'.$closingConstruct.'!s', $text, $matches))
{
# Optional, always show a particular combination on the page
self::checkSeed($seedPageName);
$find = array();
$replace = array();
foreach($matches[0] as $key => $match)
{
$choices = explode($separator, $matches[1][$key]);
if($calculate)
{
$permutations *= count($choices);
}
else
{
$find[] = $match;
$replace[] = $choices[mt_rand(0, count($choices) - 1)];
}
}
if(!$calculate)
{
# Ensure multiple instances of the same spinning combinations will spin differently
$text = self::str_replace_first($find, $replace, $text);
}
}
return $$return;
}
# The nested version allows nested spin blocks, but is slower
public static function nested($text, $seedPageName = true, $openingConstruct = '{{', $closingConstruct = '}}', $separator = '|')
{
# If we have nothing to spin just exit (don't use a regexp)
if(strpos($text, $openingConstruct) === false)
{
return $text;
}
# Find the first whole match
if(preg_match('!'.$openingConstruct.'(.+?)'.$closingConstruct.'!s', $text, $matches))
{
# Optional, always show a particular combination on the page
self::checkSeed($seedPageName);
# Only take the last block
if(($pos = mb_strrpos($matches[1], $openingConstruct)) !== false)
{
$matches[1] = mb_substr($matches[1], $pos + mb_strlen($openingConstruct));
}
# And spin it
$parts = explode($separator, $matches[1]);
$text = self::str_replace_first($openingConstruct.$matches[1].$closingConstruct, $parts[mt_rand(0, count($parts) - 1)], $text);
# We need to continue until there is nothing left to spin
return self::nested($text, $seedPageName, $openingConstruct, $closingConstruct, $separator);
}
else
{
# If we have nothing to spin just exit
return $text;
}
}
# Similar to str_replace, but only replaces the first instance of the needle
private static function str_replace_first($find, $replace, $string)
{
# Ensure we are dealing with arrays
if(!is_array($find))
{
$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment