simpler version without much js, just vanilla pure simple php (with some libs)

This commit is contained in:
Synox 2018-01-09 00:23:36 +01:00
parent e70f536b1a
commit e7f3446506
47 changed files with 1915 additions and 363 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
.idea
*.patch
node_modules

View file

@ -1,6 +1,7 @@
{
"require": {
"php-imap/php-imap": "~2.0"
"php-imap/php-imap": "~2.0",
"gnugat/PronounceableWord": "*"
},
"config": {
"vendor-dir": "src/backend-libs"

46
composer.lock generated
View file

@ -4,9 +4,51 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "18ba77805fd530e1972050e6de7cd151",
"content-hash": "357059f60b3f57be6e5f15b1df393a72",
"hash": "781cc38d2f745ec4bfba29e440111b80",
"content-hash": "70878ea12bce14861844baa8032688de",
"packages": [
{
"name": "gnugat/PronounceableWord",
"version": "2.0.0",
"source": {
"type": "git",
"url": "git@github.com:gnugat/PronounceableWord.git",
"reference": "60a19dc7148e92de35ea536b9f873b86365d48f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/gnugat/PronounceableWord/zipball/60a19dc7148e92de35ea536b9f873b86365d48f0",
"reference": "60a19dc7148e92de35ea536b9f873b86365d48f0",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"type": "library",
"autoload": {
"psr-0": {
"PronounceableWord_": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Loïc Chardonnet"
}
],
"description": "A light, customizable and simple library generating random and pronounceable words without using dictionaries or Markov chains.",
"homepage": "https://github.com/gnugat/PronounceableWord",
"keywords": [
"generator",
"pronounceable",
"word"
],
"abandoned": true,
"time": "2012-01-08 19:36:58"
},
{
"name": "php-imap/php-imap",
"version": "2.0.3",

View file

@ -2,6 +2,6 @@
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit125dddd280a32cf75b181166154246ec::getLoader();

View file

@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
'PronounceableWord_' => array($vendorDir . '/gnugat/PronounceableWord/src'),
'PhpImap' => array($vendorDir . '/php-imap/php-imap/src'),
);

View file

@ -9,6 +9,10 @@ class ComposerStaticInit125dddd280a32cf75b181166154246ec
public static $prefixesPsr0 = array (
'P' =>
array (
'PronounceableWord_' =>
array (
0 => __DIR__ . '/..' . '/gnugat/PronounceableWord/src',
),
'PhpImap' =>
array (
0 => __DIR__ . '/..' . '/php-imap/php-imap/src',

View file

@ -43,5 +43,49 @@
"mail",
"php"
]
},
{
"name": "gnugat/PronounceableWord",
"version": "2.0.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "git@github.com:gnugat/PronounceableWord.git",
"reference": "60a19dc7148e92de35ea536b9f873b86365d48f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/gnugat/PronounceableWord/zipball/60a19dc7148e92de35ea536b9f873b86365d48f0",
"reference": "60a19dc7148e92de35ea536b9f873b86365d48f0",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"time": "2012-01-08 19:36:58",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"PronounceableWord_": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Loïc Chardonnet"
}
],
"description": "A light, customizable and simple library generating random and pronounceable words without using dictionaries or Markov chains.",
"homepage": "https://github.com/gnugat/PronounceableWord",
"keywords": [
"generator",
"pronounceable",
"word"
],
"abandoned": true
}
]

View file

@ -0,0 +1 @@
/nbproject

View file

@ -0,0 +1,35 @@
Change log
==========
This file will provide the main changes between each new versions.
To get the diff for a specific change, go to https://github.com/gnugat/PronounceableWord/commit/XXX
where XXX is the change hash.
To get the diff between two versions, go to https://github.com/gnugat/PronounceableWord/compare/X.Y.Z...A.B.C
where X.Y.Z and A.B.C are the tag names.
2.0.0 (2012-01-08)
------------------
* b9b3583: compatibility woth composer;
* 01a495a: using lower probability for LinkedLetters configuration;
* 8b27028: using a dependency injection container;
* 24bd26c: using dependency injection pattern;
* fe00216: complying to PSR-0 standard;
* c6c7ea1: importing documentation from wiki.
1.0.2 (2012-01-03)
------------------
* 1e34020: updating the version number.
1.0.1 (2012-01-03)
------------------
* 3af0bff: copyright extended to 2012.
1.0.0 (2011-12-17)
------------------
* a86dcea: Initial stable release.

View file

@ -0,0 +1,27 @@
LICENSE
=======
License for the PronounceableWord PHP library
The MIT license
---------------
Copyright (c) 2011-2012 Loic Chardonnet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,107 @@
PronounceableWord PHP library
=============================
A light, customizable and simple PHP (>= 5.2) library, used to generate
randomly pronounceable words, names and passwords without using database of
existing words or big samples of text like with Markov chains.
**Warning**
Offensive or insulting words might be generated because of the random nature
of the generator (see how to manage them in
``./doc/manageOffensiveAndInsultingWords.rst``).
Installation and usage
======================
First, get the last stable version, and put it in an accessible directory.
You can use composer to do so (http://packagist.org/), by adding in the
``require`` of your file ``./composer.json`` the following entry:
``"gnugat/PronounceableWord": "*"``.
You should have a fully operationnal pronounceable word generator::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$generator = $container->getGenerator();
$word = $generator->generateWordOfGivenLength($length);
Configuration
-------------
To customize the algorithm, the letters used, the linked letters or the types,
just copy and modify as you wish the files in the
``./src/PronounceableWord/Configuration`` directory and then pass your
configuration classes to the container (see how to configure in
``./doc/configuration.rst``).
Tests
-----
Tests are done using PHPUnit (https://github.com/sebastianbergmann/phpunit/)
(>=3.5) in the ``./test`` directory (see how to test in ``./doc/tests.rst``).
Examples
--------
Here is a sample of examples that can be generated (use the
``./bin/generateExamples.php`` script for more):
======= ====== ======= ======== =========
Length 5 6 7 8
======= ====== ======= ======== =========
1 vicas panori eropops absugrit
2 ramsa verifu simbous nimpiowi
3 kiclu impriar rubleru entumecu
4 posup bivary kitocra vemolior
5 utler rugisi kanomev pactabie
======= ====== ======= ======== =========
Algorithm
=========
Basically, the library will generate a word following these rules:
1. Choose randomly a letter;
2. choose randomly a linked letter of different type;
3. choose randomly a linked letter, of different type if the last letter is
of consecutive types.
Where:
* "linked letter" is an arbitrary chosen letter that is expected to follow
well the previous letter;
* "types" would be voyels and consonants;
* "consecutive" would be a group of two letters from the same "type".
The step 3 is repeated as many times as necessary.
Documentation
=============
You can find more documentation at the following links:
* Copyright and MIT license: ``./LICENSE.rst``;
* version and change log: ``./VERSION.rst`` and ``CHANGELOG.rst``;
* technical and usage documentation: ``./doc/``.
Contributing
============
1. Fork it: https://github.com/gnugat/PronounceableWord/fork_select ;
2. create a branch (``git checkout -b my_branch``);
3. commit your changes (``git commit -am "Changes description message"``);
4. push to the branch (``git push origin my_branch``);
5. create an Issue (https://github.com/gnugat/PronounceableWord/issues) with a
link to your branch;
6. wait for it to be accepted/argued.

View file

@ -0,0 +1,10 @@
VERSION
=======
The purpose of this file is to point out the version of the PronounceableWord
library.
Current version
---------------
2.0.0

View file

@ -0,0 +1,26 @@
#!/usr/bin/env php
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../src/PronounceableWord/DependencyInjectionContainer.php';
define('MINIMUM_LENGTH', 4);
define('MAXIMUM_LENGTH', 9);
$container = new PronounceableWord_DependencyInjectionContainer();
$generator = $container->getGenerator();
$maximumGenerationNumber = 20;
for ($generationNumber = 0; $generationNumber < $maximumGenerationNumber; $generationNumber++) {
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
echo $generator->generateWordOfGivenLength($length) . "\n";
}

View file

@ -0,0 +1,21 @@
{
"name": "gnugat/PronounceableWord",
"type": "library",
"description": "A light, customizable and simple library generating random and pronounceable words without using dictionaries or Markov chains.",
"keywords": ["generator", "pronounceable", "word"],
"homepage": "https://github.com/gnugat/PronounceableWord",
"license": "MIT",
"authors": [
{
"name": "Loic Chardonnet"
}
],
"require": {
"php": ">=5.2"
},
"autoload": {
"psr-0": {
"PronounceableWord_": "src/"
}
}
}

View file

@ -0,0 +1,210 @@
Configuration
=============
To generate pronounceable words, **PronouceableWord** uses three types of
configuration:
================ ================================ ================================================
Configuration What it defines What it allows
================ ================================ ================================================
Linked letters The link between letters To know which letters can follow a letter
Letter types The types of the letters To alternate between consonants, vowels, etc...
Generator The number of consecutive types To know when to alternate the types
================ ================================ ================================================
PronouceableWord_Configuration_LinkedLetters
--------------------------------------------
This class contains only one attribute (``lettersWithLinkedLetters``), which
is an associative array:
Key
A string of only one character representing the letter.
Value
A string representing the letters supposed to follow well the **key**.
For example, having ``'b' => 'a'`` will allow to compose ``'ba'``.
PronouceableWord_Configuration_LetterTypes
------------------------------------------
This class contains only one attribute (``letterTypesWithLetters``), which is
an associative array:
Key
The name of the type.
Value
A string containing the letters of this type.
For example, defining the vowels would be: ``'vowels' => 'aeiouy'``.
PronounceableWord_Configuration_Generator
-----------------------------------------
This class contains two attributes which must be integers superior to 1.:
===================================== ==============================================================================
Attribute Example value and effect
===================================== ==============================================================================
maximumConsecutiveTypesAtTheBegining 1: if the first letter is a vowel, the second will be a consonant
maximumConsecutiveTypesInTheWord 2: if the second and third letters are vowels, the fourth will be a consonant
===================================== ==============================================================================
Default configuration
=====================
The default configuration provides a set of linked letters based on the study
of Data Compression (http://www.data-compression.com/english.shtml#second),
using there statistical study of English text.
Some changes have been applied:
* only letters with a probability superior to 0.01 have been selected;
* the letters 'j' and 'q' have been removed.
How to customize the configuration
==================================
To customize the configuration, you need to:
1. copy the configuration classes in
``./vendor/PronounceableWord/src/PronounceableWord/Configuration`` to your
project configuration (e.g. ``./Configuration``);
2. change the name of your configuration classes to avoid confusion, (e.g.
replacing the prefix ``PronounceableWord`` by ``My``);
3. change the content as you wish;
4. set the configuration attributes in the dependency injection container
with your own classes.
How to test the configuration
=============================
To make sure your customized configuration is coherent and won't make
**PronounceableWord** crash, you can test it as follow:
1. create a unit test extending the configuration test (from
``./vendor/PronounceableWord/test/PronounceableWord/Tests/Configuration``);
2. override the ``setUp`` method by initializing the ``configuration``
attribute with your own configuration class.
To learn more about how to test, see ``./doc/tests.srt``.
Full Example
============
Here is a complete example, to show how it works.
Customizing
-----------
The configuration::
<?php
// File copied: "./vendor/PronounceableWord/src/PronounceableWord/Configuration/LinkedLetters.php"
// into: "./Configuration/LinkedLetters.php"
class My_Configuration_LinkedLetters {
public $lettersWithLinkedLetters = array(
'a' => 'bc',
'b' => 'ac',
'c' => 'a0',
'0' => 'abc',
);
}
<?php
// File copied: "./vendor/PronounceableWord/src/PronounceableWord/Configuration/LetterTypes.php"
// into: "./Configuration/LetterTypes.php"
class My_Configuration_LetterTypes {
public $letterTypesWithLetters = array(
'vowels' => 'a',
'consonants' => 'bc',
'numbers' => '0',
);
}
<?php
// File copied: "./vendor/PronounceableWord/src/PronounceableWord/Configuration/Generator.php"
// into: "./Configuration/Generator.php"
class My_Configuration_Generator {
public $maximumConsecutiveTypesAtTheBegining = 1;
public $maximumConsecutiveTypesInTheWord = 2;
}
This configuration is fine:
* each letters have at least one linked letters of a different type;
* there are at least two different types;
* every letters are present in the letter types;
* the number of consecutive types are strictly positives.
Usage
-----
To use it, just set them into the container::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
require_once dirname(__FILE__) . '/Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . '/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/Configuration/Generator.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$container->configurations['LinkedLetters'] = new My_Configuration_LinkedLetters();
$container->configurations['LetterTypes'] = new My_Configuration_LetterTypes();
$container->configurations['Generator'] = new My_Configuration_Generator();
$generator = $container->getGenerator();
$word = $generator->generateWordOfGivenLength($length);
Testing
-------
To test it, create the following unit tests::
<?php
// File /test/Configuration/LinkedLettersTest.php
require_once dirname(__FILE__) . '/../../vendor/PronounceableWord/test/PronounceableWord/Tests/Configuration/LinkedLettersTest.php';
require_once dirname(__FILE__) . '/../../Configuration/LinkedLetters.php';
class My_Tests_Configuration_LinkedLettersTest extends PronounceableWord_Tests_Configuration_LinkedLettersTest {
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_LinkedLetters();
}
}
<?php
// File /test/Configuration/LetterTypesTest.php
require_once dirname(__FILE__) . '/../../vendor/PronounceableWord/test/PronounceableWord/Tests/Configuration/LetterTypesTest.php';
require_once dirname(__FILE__) . '/../../Configuration/LetterTypes.php';
class My_Tests_Configuration_LetterTypesTest extends PronounceableWord_Tests_Configuration_LetterTypesTest {
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_LetterTypes();
}
}
<?php
// File /test/Configuration/GeneratorTest.php
require_once dirname(__FILE__) . '/../../vendor/PronounceableWord/test/PronounceableWord/Tests/Configuration/GeneratorTest.php';
require_once dirname(__FILE__) . '/../../Configuration/Generator.php';
class My_Tests_Configuration_GeneratorTest extends PronounceableWord_Tests_Configuration_GeneratorTest {
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_Generator();
}
}

View file

@ -0,0 +1,59 @@
Offensive and insulting words management
========================================
Because PronounceableWord uses an algorithm using randomness,
offensive or insulting words might be generated. The best way to manage them
is to ceate a function that will filter them afterward.
These offensive words might be surrounded by other letters that would be fine
otherwise, so you should replace it by a non-offensive one instead of just
removing it.
To avoid generating unpronounceable words with this filter, try to be
consistent with the configuration.
Example
-------
Here is an example on how to manage them. With the default configuration, the
word "insult" can be generated. Let's replace it by "insalt": the letter "s"
has "a" as a linked letter, and the letter "a" has "l" has a linked letter::
<?php
// File "/OffensiveAndInsultingWords.php".
class OffensiveAndInsultingWords {
protected $offensiveAndInsultingWords = array(
'insult' => 'insalt',
);
public function filter($word) {
foreach ($this->offensiveAndInsultingWords as $offensiveAndInsultingWord => $replacement) {
$word = str_replace($offensiveAndInsultingWord, $replacement, $word);
}
return $word;
}
}
Now, after generating your words with ``PronounceableWord_Generator``, you can
use ``OffensiveAndInsultingWords`` to filter any words you might find offensive
or insulting::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/OffensiveAndInsultingWords.php';
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$generator = $container->getGenerator();
$offensiveAndInsultingWordManager = new OffensiveAndInsultingWords();
$word = $generator->generateWordOfGivenLength($length);
$word = offensiveAndInsultingWordManager->filter($word);

View file

@ -0,0 +1,175 @@
The password generator example
==============================
This page is intended to provide an example of usage and configuration, to
generate passwords with PronounceableWord.
First create your project. You should have something like::
<?php
// File "/index.php".
Installation
============
First, get the last stable version, and put it in an accessible directory::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/Generator.php';
For now, you should have a fully operationnal generator::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$generator = $container->getGenerator();
$password = $generator->generateWordOfGivenLength($length);
Configuration
=============
Let's say that the standard configuration doesn't please you, because you think
that password should also contain integers.
Linked letters configuration
----------------------------
The first thing is to create your own linked letters configuration, with
integers::
<?php
// File "./Configuration/LinkedLetters.php"
class My_Configuration_LinkedLetters {
public $lettersWithLinkedLetters = array(
'a' => 'bcdgiklmnprstvy0123456789',
'b' => 'aeilorstuy0123456789',
'c' => 'acehiklortu0123456789',
'd' => 'aeiorsu0123456789',
'e' => 'acdeilmnprstvxy0123456789',
'f' => 'aefilortu0123456789',
'g' => 'aeghilnorsu0123456789',
'h' => 'aeiortu0123456789',
'i' => 'acdefglmnorstv0123456789',
'k' => 'aeilnos0123456789',
'l' => 'adefilostuy0123456789',
'm' => 'abeimoprsuy0123456789',
'n' => 'acdegiosty0123456789',
'o' => 'cdfklmnoprstuvw0123456789',
'p' => 'aehiloprstu0123456789',
'r' => 'acdegilmnorstuy0123456789',
's' => 'acehilopstu0123456789',
't' => 'aehilorstuy0123456789',
'u' => 'abcdegilmnprst0123456789',
'v' => 'aeino0123456789',
'w' => 'aehinos0123456789',
'x' => 'acehiptu0123456789',
'y' => 'eiost0123456789',
'z' => 'aeiloyz0123456789',
'0' => 'abcdefghiklmnoprstuvwxyz0123456789',
'1' => 'abcdefghiklmnoprstuvwxyz0123456789',
'2' => 'abcdefghiklmnoprstuvwxyz0123456789',
'3' => 'abcdefghiklmnoprstuvwxyz0123456789',
'4' => 'abcdefghiklmnoprstuvwxyz0123456789',
'5' => 'abcdefghiklmnoprstuvwxyz0123456789',
'6' => 'abcdefghiklmnoprstuvwxyz0123456789',
'7' => 'abcdefghiklmnoprstuvwxyz0123456789',
'8' => 'abcdefghiklmnoprstuvwxyz0123456789',
'9' => 'abcdefghiklmnoprstuvwxyz0123456789',
);
}
Letter type configuration
-------------------------
Then create the letter types configuration with integers::
<?php
// File "./Configuration/LetterTypes.php"
class My_Configuration_LetterTypes {
public $letterTypesWithLetters = array(
'voyels' => 'aeiouy',
'consonants' => 'bcdfghklmnprstvwxz',
'integers' => '0123456789',
);
}
Adding your configuration
-------------------------
Finally, simply add your configuration into the container::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
require_once dirname(__FILE__) . './Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . './Configuration/LetterTypes.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$container->configurations['LinkedLetters'] = new My_Configuration_LinkedLetters();
$container->configurations['LetterTypes'] = new My_Configuration_LetterTypes();
$generator = $container->getGenerator();
$password = $generator->generateWordOfGivenLength($length);
Conclusion
==========
You now have a pronounceable password generator. If you want to use upper and
lower case, you should use a function aferwards::
<?php
// File "./addUppercase.php"
define('CHOOSE_LOWER_CASE', 0);
define('CHOOSE_UPPER_CASE', 1);
function addUppercase($word) {
$maximumLetterIndex = strlen($word);
for ($letterIndex = 0; $letterIndex < $maximumLetterIndex, $letterIndex++) {
$choice = rand(CHOOSE_LOWER_CASE, CHOOSE_UPPER_CASE);
if (CHOOSE_UPPER_CASE === $choice) {
$word[$letterIndex] = strtoupper($word[$letterIndex]);
}
}
return $word;
}
And::
<?php
// File "/index.php".
require_once dirname(__FILE__) . '/vendor/PronounceableWord/src/PronounceableWord/DependencyInjectionContainer.php';
require_once dirname(__FILE__) . './Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . './Configuration/LetterTypes.php';
define('MINIMUM_LENGTH', 5);
define('MAXIMUM_LENGTH', 11);
$length = rand(MINIMUM_LENGTH, MAXIMUM_LENGTH);
$container = new PronounceableWord_DependencyInjectionContainer();
$container->configurations['LinkedLetters'] = new My_Configuration_LinkedLetters();
$container->configurations['LetterTypes'] = new My_Configuration_LetterTypes();
$generator = $container->getGenerator();
$password = $generator->generateWordOfGivenLength($length);
$password = addUppercase($password);

View file

@ -0,0 +1,31 @@
Roadmap
=======
This file will establish the fetaures plan for the next versions.
2.1.0
-----
The following features must be implemented to reach the version 2.1.0:
* Choice of first letter based on the letters following 'SPACE' in the
Data Compression study: http://www.data-compression.com/english.shtml#second;
* choice of last letter based on the letters coming before 'SPACE' in the
Data Compression study: http://www.data-compression.com/english.shtml#second.
2.0.0
-----
In order to reach the version 2.0.0, the following features must be
implemented:
* moving the documentation from the Github wiki to the git repository;
* conforming to the standard PSR-0:
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md;
* using the Dependency Injection design pattern to load configuration:
http://en.wikipedia.org/wiki/Dependency_injection;
* using Dependency Injection Container;
* using, as the linked letters default configuration, letters from the Data
Compression study superior to 0.01 instead of 0.001:
http://www.data-compression.com/english.shtml#second;
* being compatible with composer.

View file

@ -0,0 +1,40 @@
Tests
=====
In order to keep PronounceableWordGenerator stable and to maintain a high
quality, tests have been written using PHPUnit >= 3.5
(https://github.com/sebastianbergmann/phpunit/).
Installation
============
Before doing any test, you must do some installations.
Installing PEAR
---------------
PEAR (http://pear.php.net/) is necessary to use PHPUnit. To install it, follow
these instructions: http://pear.php.net/manual/en/installation.getting.php
If you are on Windows, and using WAMP or EasyPHP (or maybe others web
development plateforms), you might encounter the following error::
phar "C:\wamp\bin\php\php5.3.0\PEAR\go-pear.phar" does not have a signature PHP Warning: require_once(phar://go-pear.par/index.php): failed to open stream: phar error: invalid url or non-existent phar "phar://go-pear.phar/index.php" in C:\wamp\bin\php\php5.3.0\PEAR\go-pear.phar on line 1236
Warning: require_once(phar://go-pear.par/index.php): failed to open stream: phar error: invalid url or non-existent phar "phar://go-pear.phar/index.php" in C:\wamp\bin\php\php5.3.0\PEAR\go-pear.phar on line 1236 Press any key to continue...
This is because the PHP setting "phar.require_hash" is set to "On" by default.
If you set it to "Off" in your "php.ini", you should be able to continue.
Installing PHPUnit
------------------
Once PEAR is installed, you can use it to install PHPUnit by following these
instructions: http://www.phpunit.de/manual/3.0/en/installation.html
Running the tests
=================
Tests can be run by CLI, using the following command::
phpunit ./test

View file

@ -0,0 +1,54 @@
Versionning
===========
This file will document the versionning process of the PHP library
PronounceableWord.
Version number
==============
The version number will follow the X.Y.Z format. The following table describes
the meaning of incrementation for each number:
======== =============================================================================================
Version Description
======== =============================================================================================
#.0.0 Modification impacting on the public usage
0.#.0 Modification not impacting on the public usage
0.0.# Small modification not impacting on the public usage, like bug fixes and adding of new tests
======== =============================================================================================
Branching model
===============
The PronounceableWord project uses Git to its full potential, following
the advice of this article:
http://nvie.com/posts/a-successful-git-branching-model/ .
================== =============== ================================= ====================================
Repository/Branch Pull from Merge to Description
================== =============== ================================= ====================================
origin/master Stable branch, actual release.
origin/develop origin/master origin/master Stable branch, for next release.
x/hotfix-* origin/master origin/master and origin/develop Bug fixes branch for origin/master.
x/x origin/develop origin/develop Feature branch.
================== =============== ================================= ====================================
Tags
----
Tags are created from the origin/master branch, incrementing the version number.
x/hotfix-* branches
-------------------
The repository is named x because it can be from another repository (through
forks), and the branch is called hotfix-* because it is suffixed by "hotfix-"
and named after the feature it will fix.
x/x branches
------------
The repository is named x because it can be from another repository (through
forks), and the branch is called x because it is named after the feature it
will implement.

View file

@ -0,0 +1,5 @@
<?php
class PronounceableWord_Configuration_Generator {
public $maximumConsecutiveTypesAtTheBegining = 1;
public $maximumConsecutiveTypesInTheWord = 2;
}

View file

@ -0,0 +1,7 @@
<?php
class PronounceableWord_Configuration_LetterTypes {
public $letterTypesWithLetters = array(
'voyels' => 'aeiouy',
'consonants' => 'bcdfghklmnprstvwxz',
);
}

View file

@ -0,0 +1,29 @@
<?php
class PronounceableWord_Configuration_LinkedLetters {
public $lettersWithLinkedLetters = array(
'a' => 'bcdgiklmnprstvy',
'b' => 'aeilorstuy',
'c' => 'acehiklortu',
'd' => 'aeiorsu',
'e' => 'acdeilmnprstvxy',
'f' => 'aefilortu',
'g' => 'aeghilnorsu',
'h' => 'aeiortu',
'i' => 'acdefglmnorstv',
'k' => 'aeilnos',
'l' => 'adefilostuy',
'm' => 'abeimoprsuy',
'n' => 'acdegiosty',
'o' => 'cdfklmnoprstuvw',
'p' => 'aehiloprstu',
'r' => 'acdegilmnorstuy',
's' => 'acehilopstu',
't' => 'aehilorstuy',
'u' => 'abcdegilmnprst',
'v' => 'aeino',
'w' => 'aehinos',
'x' => 'acehiptu',
'y' => 'eiost',
'z' => 'aeiloyz',
);
}

View file

@ -0,0 +1,66 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . '/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/Configuration/Generator.php';
require_once dirname(__FILE__) . '/LinkedLetters.php';
require_once dirname(__FILE__) . '/LetterTypes.php';
require_once dirname(__FILE__) . '/LastLettersConsecutiveTypes.php';
require_once dirname(__FILE__) . '/Generator.php';
class PronounceableWord_DependencyInjectionContainer {
public $configurations = array();
public $classNames = array();
public function __construct() {
$this->configurations['Generator'] = new PronounceableWord_Configuration_Generator();
$this->configurations['LinkedLetters'] = new PronounceableWord_Configuration_LinkedLetters();
$this->configurations['LetterTypes'] = new PronounceableWord_Configuration_LetterTypes();
$this->classNames['LinkedLetters'] = 'PronounceableWord_LinkedLetters';
$this->classNames['LetterTypes'] = 'PronounceableWord_LetterTypes';
$this->classNames['LastLettersConsecutiveTypes'] = 'PronounceableWord_LastLettersConsecutiveTypes';
$this->classNames['Generator'] = 'PronounceableWord_Generator';
}
public function getGenerator() {
$generatorClass = $this->classNames['Generator'];
$generatorInstance = new $generatorClass(
$this->getLinkedLetters(),
$this->getLetterTypes(),
$this->getLastLettersConsecutiveTypes(),
$this->configurations['Generator']
);
return $generatorInstance;
}
public function getLinkedLetters() {
$linkedLettersClass = $this->classNames['LinkedLetters'];
$linkedLettersInstance = new $linkedLettersClass($this->configurations['LinkedLetters']);
return $linkedLettersInstance;
}
public function getLetterTypes() {
$lettersTypesClass = $this->classNames['LetterTypes'];
$lettersTypesInstance = new $lettersTypesClass($this->configurations['LetterTypes']);
return $lettersTypesInstance;
}
public function getLastLettersConsecutiveTypes() {
$lastLettersConsecutiveTypesClass = $this->classNames['LastLettersConsecutiveTypes'];
$lastLettersConsecutiveTypesInstance = new $lastLettersConsecutiveTypesClass($this->getLetterTypes());
return $lastLettersConsecutiveTypesInstance;
}
}

View file

@ -0,0 +1,76 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
class PronounceableWord_Generator {
protected $word;
protected $length;
protected $linkedLetters;
protected $letterTypes;
protected $lastLettersConsecutiveTypes;
protected $configuration;
public function __construct($linkedLetter, $letterTypes, $lastLettersConsecutiveTypes, $configuration) {
$this->linkedLetters = $linkedLetter;
$this->letterTypes = $letterTypes;
$this->lastLettersConsecutiveTypes = $lastLettersConsecutiveTypes;
$this->configuration = $configuration;
}
public function generateWordOfGivenLength($givenLength) {
$this->word = '';
$this->length = 0;
for ($letterNumber = 0; $letterNumber < $givenLength; $letterNumber++) {
$this->word .= $this->pickNextLetter();
$this->length = strlen($this->word);
}
return $this->word;
}
protected function pickNextLetter() {
$pickedLetter = '';
if (0 === $this->length) {
$pickedLetter = $this->pickFirstLetter();
} elseif ($this->length <= $this->configuration->maximumConsecutiveTypesAtTheBegining) {
$pickedLetter = $this->pickLinkedLetterOfDifferentType($this->word[0]);
} else {
$pickedLetter = $this->pickLinkedLetterOfDifferentTypeIfLastLettersAreOfConsecutiveTypes();
}
return $pickedLetter;
}
protected function pickFirstLetter() {
return $this->linkedLetters->pickLetter();
}
protected function pickLinkedLetterOfDifferentType($letter) {
$letterType = $this->letterTypes->getLetterType($letter);
$lettersToAvoid = $this->letterTypes->getLettersOfGivenType($letterType);
return $this->linkedLetters->pickLinkedLetterDifferentFromGivenLetters($letter, $lettersToAvoid);
}
protected function pickLinkedLetterOfDifferentTypeIfLastLettersAreOfConsecutiveTypes() {
$lastLetter = $this->word[$this->length - 1];
$consecutiveTypes = $this->lastLettersConsecutiveTypes->countFromWord($this->word);
$pickedLetter = '';
if ($consecutiveTypes === $this->configuration->maximumConsecutiveTypesInTheWord) {
$pickedLetter = $this->pickLinkedLetterOfDifferentType($lastLetter);
} else {
$pickedLetter = $this->linkedLetters->pickLinkedLetter($lastLetter);
}
return $pickedLetter;
}
}

View file

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
class PronounceableWord_LastLettersConsecutiveTypes {
protected $letterTypes;
public function __construct($letterTypes) {
$this->letterTypes = $letterTypes;
}
public function countFromWord($word) {
$letterIndex = strlen($word) - 1;
$letter = $word[$letterIndex];
$type = $this->letterTypes->getLetterType($letter);
$consecutiveTypesCount = 1;
for ($letterIndex = $letterIndex - 1; $letterIndex >= 0; $letterIndex--) {
$letter = $word[$letterIndex];
if ($this->letterTypes->getLetterType($letter) !== $type) {
break;
}
$consecutiveTypesCount++;
}
return $consecutiveTypesCount;
}
}

View file

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
class PronounceableWord_LetterTypes {
protected $configuration;
public function __construct($configuration) {
$this->configuration = $configuration;
}
public function getLetterType($letter) {
$type = '';
foreach ($this->configuration->letterTypesWithLetters as $letterType => $letters) {
if (false !== strpos($letters, $letter)) {
$type = $letterType;
break;
}
}
return $type;
}
public function getLettersOfGivenType($type) {
return $this->configuration->letterTypesWithLetters[$type];
}
}

View file

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
class PronounceableWord_LinkedLetters {
protected $configuration;
public function __construct($configuration) {
$this->configuration = $configuration;
}
public function pickLetter() {
$pickedLetter = array_rand($this->configuration->lettersWithLinkedLetters);
return $pickedLetter;
}
public function pickLinkedLetter($letter) {
$linkedLetters = $this->configuration->lettersWithLinkedLetters[$letter];
return $this->pickLetterFromGivenLetters($linkedLetters);
}
protected function pickLetterFromGivenLetters($letters) {
$minLetterIndex = 0;
$maxLetterIndex = strlen($letters) - 1;
$pickedLetterIndex = rand($minLetterIndex, $maxLetterIndex);
$pickedLetter = $letters[$pickedLetterIndex];
return $pickedLetter;
}
public function pickLinkedLetterDifferentFromGivenLetters($letter, $letters) {
$linkedLetters = $this->configuration->lettersWithLinkedLetters[$letter];
$letterChoices = $this->removeGivenLettersFromGivenLinkedLetters($letters, $linkedLetters);
return $this->pickLetterFromGivenLetters($letterChoices);
}
protected function removeGivenLettersFromGivenLinkedLetters($letters, $linkedLetters) {
$maximumLetterIndex = strlen($letters);
for ($letterIndex = 0; $letterIndex < $maximumLetterIndex; $letterIndex++) {
$linkedLetters = str_replace($letters[$letterIndex], '', $linkedLetters);
}
return $linkedLetters;
}
}

View file

@ -0,0 +1,27 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/Configuration/Generator.php';
class PronounceableWord_Tests_Configuration_GeneratorTest extends PHPUnit_Framework_TestCase {
protected $minimumPositiveNumber = 1;
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_Generator();
}
public function testIsMaximumConsecutiveTypesAtTheBeginingPositive() {
$this->assertGreaterThanOrEqual($this->minimumPositiveNumber, $this->configuration->maximumConsecutiveTypesAtTheBegining);
}
public function testIsMaximumConsecutiveTypesInTheWordPositive() {
$this->assertGreaterThanOrEqual($this->minimumPositiveNumber, $this->configuration->maximumConsecutiveTypesInTheWord);
}
}

View file

@ -0,0 +1,37 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/Configuration/LetterTypes.php';
class PronounceableWord_Tests_Configuration_LetterTypesTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_LetterTypes();
}
public function testAreLettersInOnlyOneType() {
foreach ($this->configuration->letterTypesWithLetters as $currentType => $lettersOfCurrentType) {
$maximumLetterIndex = strlen($lettersOfCurrentType);
$areLettersInOnlyOneType = true;
foreach ($this->configuration->letterTypesWithLetters as $checkedType => $lettersOfCheckedType) {
if ($currentType !== $checkedType) {
for ($letterIndex = 0; $letterIndex < $maximumLetterIndex; $letterIndex++) {
$isLetterInLetters = strpos($lettersOfCheckedType, $lettersOfCurrentType[$letterIndex]);
if (false !== $isLetterInLetters) {
$areLettersInOnlyOneType = false;
break 2;
}
}
}
}
$this->assertTrue($areLettersInOnlyOneType);
}
}
}

View file

@ -0,0 +1,58 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/LetterTypes.php';
class PronounceableWord_Tests_Configuration_LinkedLettersAndTypesTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$this->letterTypesConfiguration = new PronounceableWord_Configuration_LetterTypes();
$this->linkedLettersConfiguration = new PronounceableWord_Configuration_LinkedLetters();
}
public function testAreAllLettersFromLinkedLettersInLettersFromLetterTypes() {
foreach ($this->linkedLettersConfiguration->lettersWithLinkedLetters as $letter => $linkedLettersToIgnore) {
$isLetterInTypes = false;
foreach ($this->letterTypesConfiguration->letterTypesWithLetters as $lettersOfType) {
$isLetterInLetters = strpos($lettersOfType, $letter);
if (false !== $isLetterInLetters) {
$isLetterInTypes = true;
break;
}
}
$this->assertTrue($isLetterInTypes);
}
}
public function testHaveLettersAtLeastOneLinkedLetterOfDifferentType() {
$letterTypes = new PronounceableWord_LetterTypes($this->letterTypesConfiguration);
$linkedLettersConfiguration = new PronounceableWord_Configuration_LinkedLetters();
foreach ($this->linkedLettersConfiguration->lettersWithLinkedLetters as $letter => $linkedLetters) {
$letterType = $letterTypes->getLetterType($letter);
$hasOneDifferentType = false;
$maximumLetterIndex = strlen($linkedLetters);
for ($letterIndex = 0; $letterIndex < $maximumLetterIndex; $letterIndex++) {
$linkedLetterType = $letterTypes->getLetterType($linkedLetters[$letterIndex]);
if ($letterType !== $linkedLetterType) {
$hasOneDifferentType = true;
break;
}
}
$this->assertTrue($hasOneDifferentType);
}
}
}

View file

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../../src/PronounceableWord/Configuration/LinkedLetters.php';
class PronounceableWord_Tests_Configuration_LinkedLettersTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$this->configuration = new PronounceableWord_Configuration_LinkedLetters();
}
public function testAreAllLettersInAtLeastOneLinkedLetters() {
foreach ($this->configuration->lettersWithLinkedLetters as $letter => $linkedLettersToIgnore) {
$isInAtLeastOneLinkedLetters = false;
foreach ($this->configuration->lettersWithLinkedLetters as $letterToIgnore => $linkedLetters) {
$isLetterInLinkedLetters = strpos($linkedLetters, $letter);
if (false !== $isLetterInLinkedLetters) {
$isInAtLeastOneLinkedLetters = true;
break;
}
}
$this->assertTrue($isInAtLeastOneLinkedLetters);
}
}
public function testAreAllLinkedLettersInLetters() {
foreach ($this->configuration->lettersWithLinkedLetters as $letterToIgnore => $linkedLetters) {
$isLinkedLetterInLetters = false;
foreach ($this->configuration->lettersWithLinkedLetters as $letter => $linkedLettersToIgnore) {
$isLetterInLinkedLetters = strpos($linkedLetters, $letter);
if (false !== $isLetterInLinkedLetters) {
$isInAtLeastOneLinkedLetters = true;
break;
}
}
$this->assertTrue($isInAtLeastOneLinkedLetters);
}
}
}

View file

@ -0,0 +1,44 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/DependencyInjectionContainer.php';
class PronounceableWord_Tests_DependencyInjectionContainerTest extends PHPUnit_Framework_TestCase {
public function testClassNames() {
$container = new PronounceableWord_DependencyInjectionContainer();
foreach ($container->classNames as $classType => $className) {
$expectedClassName = 'PronounceableWord_' . $classType;
$this->assertSame($expectedClassName, $className);
}
}
public function testClassNamesAndInstances() {
$container = new PronounceableWord_DependencyInjectionContainer();
foreach ($container->classNames as $classType => $className) {
$getMethodName = 'get' . $classType;
$instance = $container->{$getMethodName}();
$this->assertInstanceOf($className, $instance);
}
}
public function testConfigurations() {
$container = new PronounceableWord_DependencyInjectionContainer();
foreach ($container->configurations as $className => $configurationInstance) {
$configurationClassName = 'PronounceableWord_Configuration_' . $className;
$this->assertInstanceOf($configurationClassName, $configurationInstance);
}
}
}

View file

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/Generator.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LinkedLetters.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LastLettersConsecutiveTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Generator.php';
class PronounceableWord_Tests_GeneratorTest extends PHPUnit_Framework_TestCase {
public function testGeneratedLength() {
$linkedLettersConfiguration = new PronounceableWord_Configuration_LinkedLetters();
$letterTypesConfiguration = new PronounceableWord_Configuration_LetterTypes();
$generatorConfiguration = new PronounceableWord_Configuration_Generator();
$linkedLetters = new PronounceableWord_LinkedLetters($linkedLettersConfiguration);
$letterTypes = new PronounceableWord_LetterTypes($letterTypesConfiguration);
$lastLettersConsecutiveTypes = new PronounceableWord_LastLettersConsecutiveTypes($letterTypes);
$maximumLength = 100;
for ($length = 1; $length <= $maximumLength; $length++) {
$generator = new PronounceableWord_Generator($linkedLetters, $letterTypes, $lastLettersConsecutiveTypes, $generatorConfiguration);
$generatedWord = $generator->generateWordOfGivenLength($length);
$this->assertEquals($length, strlen($generatedWord));
}
}
}

View file

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LastLettersConsecutiveTypes.php';
class PronounceableWord_Tests_LastLettersConsecutiveTypesTest extends PHPUnit_Framework_TestCase {
public function testCountFromWordOfOneType() {
$letterTypesConfiguration = new PronounceableWord_Configuration_LetterTypes();
$letterTypes = new PronounceableWord_LetterTypes($letterTypesConfiguration);
$lastLettersConsecutiveTypes = new PronounceableWord_LastLettersConsecutiveTypes($letterTypes);
foreach ($letterTypesConfiguration->letterTypesWithLetters as $letterType => $letters) {
$maximumLetterNumber = strlen($letters);
$word = '';
for ($letterNumber = 1; $letterNumber < $maximumLetterNumber; $letterNumber++) {
$letter = rand(0, strlen($letters) - 1);
$word .= $letters[$letter];
$this->assertSame($letterNumber, $lastLettersConsecutiveTypes->countFromWord($word));
}
}
}
public function testCountFromWordOfMultipleTypes() {
$letterTypesConfiguration = new PronounceableWord_Configuration_LetterTypes();
$letterTypes = new PronounceableWord_LetterTypes($letterTypesConfiguration);
$lastLettersConsecutiveTypes = new PronounceableWord_LastLettersConsecutiveTypes($letterTypes);
foreach ($letterTypesConfiguration->letterTypesWithLetters as $letterType => $letters) {
$maximumLetterNumber = strlen($letters);
foreach ($letterTypesConfiguration->letterTypesWithLetters as $otherLetterType => $otherLetters) {
if ($otherLetterType != $letterType) {
$word = $otherLetters;
break;
}
}
for ($letterNumber = 1; $letterNumber < $maximumLetterNumber; $letterNumber++) {
$letter = rand(0, strlen($letters) - 1);
$word .= $letters[$letter];
$this->assertSame($letterNumber, $lastLettersConsecutiveTypes->countFromWord($word));
}
}
}
}

View file

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/LetterTypes.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LetterTypes.php';
class PronounceableWord_Tests_LetterTypesTest extends PHPUnit_Framework_TestCase {
public function testGetLetterType() {
$configuration = new PronounceableWord_Configuration_LetterTypes();
$letterTypes = new PronounceableWord_LetterTypes($configuration);
foreach ($configuration->letterTypesWithLetters as $letterType => $letters) {
$maximumLetterIndex = strlen($letters);
for ($letterIndex = 0; $letterIndex < $maximumLetterIndex; $letterIndex++) {
$letter = $letters[$letterIndex];
$this->assertSame($letterType, $letterTypes->getLetterType($letter));
}
}
}
public function testGetLettersOfGivenType() {
$configuration = new PronounceableWord_Configuration_LetterTypes();
$letterTypes = new PronounceableWord_LetterTypes($configuration);
foreach ($configuration->letterTypesWithLetters as $letterType => $letters) {
$this->assertSame($letters, $letterTypes->getLettersOfGivenType($letterType));
$maximumLetterIndex = strlen($letters);
}
}
public function testIsThereAtLeastTwoTypes() {
$configuration = new PronounceableWord_Configuration_LetterTypes();
$minimumLetterTypesNumber = 2;
$this->assertGreaterThanOrEqual($minimumLetterTypesNumber, $configuration->letterTypesWithLetters);
}
}

View file

@ -0,0 +1,68 @@
<?php
/*
* This file is part of the PronounceableWord library.
*
* (c) Loic Chardonnet
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/Configuration/LinkedLetters.php';
require_once dirname(__FILE__) . '/../../../src/PronounceableWord/LinkedLetters.php';
class PronounceableWord_Tests_LinkedLettersTest extends PHPUnit_Framework_TestCase {
public function testPickLetter() {
$configuration = new PronounceableWord_Configuration_LinkedLetters();
$linkedLetters = new PronounceableWord_LinkedLetters($configuration);
$maximumTestNumber = 1000;
for ($currentTestNumber = 0; $currentTestNumber < $maximumTestNumber; $currentTestNumber++) {
$chosenLetter = $linkedLetters->pickLetter();
$this->assertArrayHasKey($chosenLetter, $configuration->lettersWithLinkedLetters);
}
}
public function testPickLinkedLetter() {
$configuration = new PronounceableWord_Configuration_LinkedLetters();
$linkedLetters = new PronounceableWord_LinkedLetters($configuration);
$maximumTestNumber = 1000;
foreach ($configuration->lettersWithLinkedLetters as $currentLetter => $currentLinkedLetters) {
for ($currentTestNumber = 0; $currentTestNumber < $maximumTestNumber; $currentTestNumber++) {
$chosenLinkedLetter = $linkedLetters->pickLinkedLetter($currentLetter);
$isChosenLetterInLinkedLetters = strpos($currentLinkedLetters, $chosenLinkedLetter);
$this->assertNotEquals(false, $isChosenLetterInLinkedLetters);
}
}
}
public function testPickLinkedLetterDifferentFromGivenLetters() {
$configuration = new PronounceableWord_Configuration_LinkedLetters();
$linkedLetters = new PronounceableWord_LinkedLetters($configuration);
$maximumTestNumber = 1000;
foreach ($configuration->lettersWithLinkedLetters as $currentLetter => $currentLinkedLetters) {
for ($currentTestNumber = 0; $currentTestNumber < $maximumTestNumber; $currentTestNumber++) {
$chosenLinkedLetter = $linkedLetters->pickLinkedLetterDifferentFromGivenLetters($currentLetter, $currentLetter);
$isChosenLetterInLinkedLetters = strpos($currentLinkedLetters, $chosenLinkedLetter);
$isChosenLetterDifferentThanCurrentLetter = false;
if ($chosenLinkedLetter !== $currentLetter) {
$isChosenLetterDifferentThanCurrentLetter = true;
}
$isChosenLetterValid = false;
if (false !== $isChosenLetterInLinkedLetters && true === $isChosenLetterDifferentThanCurrentLetter) {
$isChosenLetterValid = true;
}
$this->assertTrue($isChosenLetterValid);
}
}
}
}

View file

@ -22,10 +22,10 @@ function error($status, $text) {
/**
* print all mails for the given $user.
* @param $username string username
* @param $address string email address
* @return array
*/
function print_emails($username, $address) {
function get_emails($address) {
global $mailbox;
// Search for mails with the recipient $address in TO or CC.
@ -34,8 +34,7 @@ function print_emails($username, $address) {
$mail_ids = array_merge($mailsIdsTo, $mailsIdsCc);
$emails = _load_emails($mail_ids, $address);
header('Content-type: application/json');
print(json_encode(array("mails" => $emails, 'username' => $username, 'address' => $address)));
return $emails;
}
@ -126,6 +125,25 @@ function _clean_username($username) {
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
}
function _clean_domain($username) {
$username = strtolower($username);
$username = preg_replace('/^.*@/', "", $username); // remove part before @
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
}
function redirect_to_random($domains) {
$wordLength = rand(3, 8);
$container = new PronounceableWord_DependencyInjectionContainer();
$generator = $container->getGenerator();
$word = $generator->generateWordOfGivenLength($wordLength);
$nr = rand(51, 91);
$name = $word . $nr;
$domain = $domains[array_rand($domains)];
header("location: ?address=$name@$domain");
}
/**
* deletes messages older than X days.
*/
@ -139,30 +157,11 @@ function delete_old_messages() {
$mailbox->expungeDeletedMails();
}
// Never cache requests:
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
if (isset($_GET['username'])) {
// perform common validation:
$username = _clean_username($_GET['username']);
if (strlen($username) === 0) {
error(400, 'invalid username');
}
$address = $username . "@" . $config['mailHostname'];
// simple router:
if (isset($_GET['download_email_id'])) {
download_email($_GET['download_email_id'], $address);
} else if (isset($_GET['delete_email_id'])) {
delete_email($_GET['delete_email_id'], $address);
} else {
print_emails($username, $address);
}
} else {
error(400, 'invalid action');
}
//
//// Never cache requests:
//header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
//header("Cache-Control: post-check=0, pre-check=0", false);
//header("Pragma: no-cache");
// run on every request
delete_old_messages();

View file

@ -1,12 +0,0 @@
[ec-stickyfill] {
position: -webkit-sticky;
position: sticky;
top: 0px;
}
[ec-stickyfill]:before,
[ec-stickyfill]:after {
content: '';
display: table;
}

View file

@ -1,8 +0,0 @@
/**
* An Angular directive for stickyfill (position sticky polyfill)
*
* @version v0.1.0 - 2016-08-31
* @author Corey Wilson <corey@eastcodes.com>
* @license Unlicense, http://unlicense.org/
*/
!function(e,i){"use strict";if("function"==typeof define&&define.amd)define(["angular","stickyfill"],i);else{if("undefined"==typeof module||"object"!=typeof module.exports)return i(e.angular,e.Stickyfill);module.exports=i(require("angular"),require("stickyfill"))}}(window,function(e,i){"use strict";function t(){function e(e,t,n){if("object"!=typeof i)throw new Error("stickyfill.js not loaded");i.add(t[0]),e.$on("$destroy",function(){i.remove(t[0])})}var t={link:e,restrict:"A"};return t}if("function"==typeof i)var i=i();var n="ec.stickyfill";return e.module(n,[]).directive("ecStickyfill",t),n});

View file

@ -1,137 +0,0 @@
// config:
var reload_interval_ms = 10000;
var backend_url = './backend.php';
function generateRandomUsername() {
var username = "";
if (chance.bool()) {
username += chance.first();
if (chance.bool()) {
username += chance.last();
}
} else {
username += chance.word({syllables: 3})
}
if (chance.bool()) {
username += chance.integer({min: 30, max: 99});
}
return username.toLowerCase();
}
var app = angular.module('app', ["ngSanitize"]);
// http://stackoverflow.com/a/20033625/79461
app.filter("nl2br", function () {
return function (data) {
if (!data) return data;
return data.replace(/\r?\n/g, '<br/>');
}
}
);
// http://stackoverflow.com/a/20033625/79461
app.filter("autolink", function () {
return function (data) {
return Autolinker.link(data, {truncate: {length: 50, location: 'middle', newWindow: true}});
}
});
app.controller('MailboxController', ["$interval", "$http", "$log", function ($interval, $http, $log) {
var self = this;
self.backend_url = backend_url;
self.updateUsername = function (username) {
username = username.replace(/[@].*$/, ''); // remove part after "@"
if (self.username !== username) {
// changed
self.username = username;
hasher.setHash(self.username);
if (self.username.length > 0) {
self.address = self.username; // use username until real address has been loaded
self.updateMails();
} else {
self.randomize();
}
}
self.inputFieldUsername = self.username;
};
self.randomize = function () {
self.updateUsername(generateRandomUsername());
};
self.onHashChange = function (hash) {
self.updateUsername(hash);
};
self.$onInit = function () {
hasher.changed.add(self.onHashChange.bind(self));
hasher.initialized.add(self.onHashChange.bind(self)); //add initialized listener (to grab initial value in case it is already set)
hasher.init(); //initialize hasher (start listening for history changes)
$interval(self.updateMails, reload_interval_ms);
};
self.updateMails = function () {
if (self.username) {
self.loadEmailsAsync(self.username);
}
};
self.loadEmailsAsync = function (username) {
$http.get(backend_url, {params: {username: username}})
.then(function successCallback(response) {
if (response.data.mails) {
self.error = null;
self.mails = response.data.mails;
self.address = response.data.address;
self.username = response.data.username;
if (self.inputFieldUsername === self.username) {
self.inputFieldUsername = self.address;
}
} else {
self.error = {
title: "JSON_ERROR",
desc: "The JSON from the response can not be read.",
detail: response
};
$log.error(response);
}
}, function errorCallback(response) {
$log.error(response, this);
self.error = {
title: "HTTP_ERROR",
desc: "There is a problem with loading the data. (HTTP_ERROR).",
detail: response
};
});
};
self.deleteMail = function (mail, index) {
// instantly remove from frontend.
self.mails.splice(index, 1);
// remove on backend.
var firstTo = Object.keys(mail.to)[0];
$http.get(backend_url, {params: {username: firstTo, delete_email_id: mail.id}})
.then(
function successCallback(response) {
self.updateMails();
},
function errorCallback(response) {
$log.error(response, this);
self.error = {
title: "HTTP_ERROR",
desc: "There is a problem with deleting the mail. (HTTP_ERROR).",
detail: response
};
});
};
// Initial load
self.updateMails()
}]);

View file

@ -3,22 +3,20 @@
// set your time zone:
date_default_timezone_set('Europe/Paris');
// enable while testing:
error_reporting(E_ALL);
// enable in production:
// error_reporting(0);
error_reporting(0);
// enable while testing:
//error_reporting(E_ALL);
// configure this option if you want to allow requests from clients from other domains:
// see https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
// header("Access-Control-Allow-Origin: *");
// Change IMAP settings (check SSL flags on http://php.net/manual/en/function.imap-open.php)
$config['imap']['url'] = '{example.com/imap/ssl}INBOX';
$config['imap']['username'] = "test";
$config['imap']['password'] = "test";
$config['imap']['url'] = '{imap.example.com/imap/ssl}INBOX';
$config['imap']['username'] = "myuser";
$config['imap']['password'] = "mypassword";
// email domain, usually different from imap hostname:
$config['mailHostname'] = "example.com";
// email domains, usually different from imap hostname:
$config['domains'] = array('mydomain.com', 'example.com');
// When to delete old messages?
$config['delete_messages_older_than'] = '30 days ago';

View file

@ -1,150 +0,0 @@
<!doctype html>
<html lang="de" ng-app="app" ng-strict-di>
<head>
<meta charset="utf-8">
<title>Mailbox</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="description" content="Mailbox">
<link rel="shortcut icon" href="favicon.gif" type="image/x-icon">
<link rel="stylesheet" href="client-libs/style.css">
<link rel="stylesheet" href="client-libs/spinner.css">
<link rel="stylesheet" href="client-libs/angular-stickyfill-0.1.0/angular-stickyfill.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
</head>
<body>
<div ng-controller="MailboxController as $ctrl" ng-cloak>
<header>
<div class="container">
<form ng-submit="$ctrl.updateUsername($ctrl.inputFieldUsername)">
<small id="emailHelp" class="form-text text-muted">
You have <span class="tag tag-pill tag-default">{{$ctrl.mails.length}}</span> mails in your
mailbox:
</small>
<div class="form-group row">
<div class="col-sm-8">
<input id="inputFieldUsername" ng-model="$ctrl.inputFieldUsername"
placeholder="new username"
type="text" class="form-control form-control-lg" onclick="this.select()"/>
</div>
<div class="col-sm-2">
<button id="openRandomButton" ng-click="$ctrl.randomize()" type="button"
class="btn btn-outline-primary">open random
</button>
</div>
</div>
</form>
</div>
</header>
<main>
<div class="container min-height">
<div ng-if="$ctrl.error" class="alert alert-danger" role="alert">
<p><strong>Sorry, there was a problem. </strong></p>
<p> {{$ctrl.error.desc}} </p>
<div>
<pre>{{$ctrl.error.detail|json}}</pre>
</div>
<p> If you are the developer you might want to check the developer tools console of your web
browser and your php error logs. </p>
</div>
<div ng-if="$ctrl.username && $ctrl.mails.length == 0">
<div class="card waiting-screen">
<div class="card-block">
<p class="lead">Your mailbox <strong>{{$ctrl.address}}</strong> is ready. </p>
<p>Emails will appear here automatically. They will be deleted after 30 days.</p>
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
</div>
</div>
<div ng-if="$ctrl.username" ng-repeat="mail in $ctrl.mails | orderBy:'-date' track by $index"
class="email-table">
<div class="card email">
<div class="card-block header-shadow sticky-header" ec-stickyfill ng-init="htmlTabActive=false">
<div class="row">
<div class="col-sm-8">
<h3 class="card-title">{{mail.subject}}</h3>
</div>
<div class="col-sm-4 text-right">
<form class="form-inline float-xs-right">
<button ng-show="htmlTabActive" class="btn btn-outline-info btn-sm "
ng-click="htmlTabActive=false">show text
</button>
<button ng-show="mail.textHtml && !htmlTabActive"
class="btn btn-outline-info btn-sm"
ng-click="htmlTabActive=true">show html
</button>
<a role="button" class="btn btn-sm btn-outline-primary "
href="{{$ctrl.backend_url}}?download_email_id={{mail.id}}&username={{$ctrl.username}}"
download="true">Download
</a>
<button ng-click="$ctrl.deleteMail(mail, $index)" type="button"
class="btn btn-sm btn-outline-danger">Delete
</button>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-8">
<h6 class="card-subtitle mt-1 text-muted">{{mail.fromName}}
&lt;{{mail.fromAddress}}&gt;</h6>
</div>
<div class="col-sm-4">
<h6 class="card-subtitle mt-1 text-muted" style="text-align: right">{{mail.date}}</h6>
</div>
</div>
</div>
<div class="card-block">
<h6 class="card-subtitle text-muted">To: {{mail.toString}}</h6>
<h6 ng-if="mail.cc" ng-repeat="(address,name) in mail.cc" class="card-subtitle text-muted">CC:
{{address}}</h6>
<div class="mt-2 card-text">
<div ng-if="!htmlTabActive" ng-bind-html="mail.textPlain | nl2br | autolink "></div>
<div ng-if="htmlTabActive" ng-bind-html="mail.textHtml"></div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<footer>
<p>Powered by <a href="https://github.com/synox/disposable-mailbox"><strong>synox/disposable-mailbox</strong></a>
| <a href="https://github.com/synox/disposable-mailbox"><span class="octicon octicon-mark-github"></span> Fork
me on github</a></p>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-sanitize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/autolinker/1.2.0/Autolinker.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/1.0.4/chance.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stickyfill/1.1.4/stickyfill.min.js"></script>
<script src="client-libs/angular-stickyfill-0.1.0/angular-stickyfill.js"></script>
<script src="client-libs/index.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-signals/1.0.0/js-signals.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/hasher/1.2.0/hasher.js"></script>
</body>
</html>

240
src/index.php Normal file
View file

@ -0,0 +1,240 @@
<?php
require_once('backend.php');
if (isset($_GET['random'])) {
redirect_to_random($config['domains']);
die();
} elseif (isset($_GET['username']) && isset($_GET['domain'])) {
$username = filter_input(INPUT_GET, 'username', FILTER_SANITIZE_EMAIL);
$domain = filter_input(INPUT_GET, 'domain', FILTER_SANITIZE_EMAIL);
header("location: ?address=$username@$domain");
die();
} elseif (!isset($_GET['address'])) {
error(400, 'invalid action');
} else {
// perform common validation:
$address = filter_input(INPUT_GET, 'address', FILTER_SANITIZE_EMAIL);
$username = _clean_username($address);
$userDomain = _clean_domain($address);
if (strlen($address) === 0) {
error(400, 'invalid username');
}
if (strlen($userDomain) === 0 || !in_array($userDomain, $config['domains'])) {
error(400, 'invalid domain');
}
// simple router:
if (isset($_GET['download_email_id'])) {
download_email($_GET['download_email_id'], $address);
die();
}
if (isset($_GET['delete_email_id'])) {
$delete_email_id = filter_input(INPUT_GET, 'delete_email_id', FILTER_SANITIZE_NUMBER_INT);
delete_email($delete_email_id, $address);
}
// print emails:
$emails = get_emails($address);
}
?>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mailbox <?php echo $address ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="spinner.css">
<script src="turbolinks.js"></script>
<meta name="turbolinks-cache-control" content="no-preview">
<script>
// https://stackoverflow.com/a/44353026
var reloadWithTurbolinks = (function () {
var scrollPosition;
function reload() {
scrollPosition = [window.scrollX, window.scrollY];
Turbolinks.visit(window.location.toString(), {action: 'replace'})
}
document.addEventListener('turbolinks:load', function () {
if (scrollPosition) {
window.scrollTo.apply(window, scrollPosition);
scrollPosition = null
}
});
return reload
})();
setInterval(function () {
reloadWithTurbolinks();
}, 10000)
</script>
</head>
<body data-turbolinks="false">
<header>
<div class="container">
<small class="form-text text-muted">
change username:
</small>
<form action="?" method="get">
<div class="form-group row">
<div class="col-sm-4">
<input id="username" data-turbolinks-permanent class="form-control form-control-lg" name="username"
value="<?php echo $username ?>">
</div>
<div class="col-sm-3">
<select id="domain" data-turbolinks-permanent class="form-control form-control-lg" name="domain">
<?php
foreach ($config['domains'] as $domain) {
$selected = $domain === $userDomain ? ' selected ' : '';
print "<option value='$domain' $selected>@$domain</option>";
}
?>
</select>
</div>
<div class="col-sm-3 random-column">
<span>or &nbsp;</span>
<a role="button" href="?random=true" class="btn btn-outline-primary">generate random
</a>
</div>
</div>
</form>
</div>
</header>
<main>
<div class="container min-height">
<?php
if (empty($emails)) {
?>
<div>
<div class="card waiting-screen">
<div class="card-block">
<p class="lead">Your mailbox <strong
><?php echo $address ?></strong> is ready. </p>
<p>Emails will appear here automatically. They will be deleted after 30
days.</p>
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
</div>
</div>
<?php
} else {
foreach ($emails as $email) {
?>
<div class="email-table">
<div class="card email">
<div class="card-block header-shadow sticky-header">
<div class="row">
<div class="col-sm-8">
<h3 class="card-title">
<?php echo filter_var($email->subject, FILTER_SANITIZE_SPECIAL_CHARS); ?>
</h3>
</div>
<div class="col-sm-4 text-right">
<form class="form-inline float-xs-right">
<!-- <button class="btn btn-outline-info btn-sm">show html-->
<!-- </button>-->
<a class="btn btn-sm btn-outline-primary " download="true"
role="button"
href="?download_email_id=<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>&amp;address=<?php echo $address ?>">Download
</a>
<!-- <button class="btn btn-sm btn-outline-danger" type="button">-->
<!-- Delete-->
<!-- </button>-->
</form>
</div>
</div>
<div class="row">
<div class="col-sm-8">
<h6 class="card-subtitle mt-1 text-muted">
<?php
echo filter_var($email->fromName, FILTER_SANITIZE_SPECIAL_CHARS);
echo ' &lt;';
echo filter_var($email->fromAddress, FILTER_SANITIZE_SPECIAL_CHARS);
echo '&gt;';
?>
</h6>
</div>
<div class="col-sm-4">
<h6 class="card-subtitle mt-1 text-muted"
style="text-align: right">
<?php echo filter_var($email->date, FILTER_SANITIZE_SPECIAL_CHARS); ?>
</h6>
</div>
</div>
</div>
<div class="card-block">
<h6 class="card-subtitle text-muted">
To: <?php echo filter_var($email->toString, FILTER_SANITIZE_SPECIAL_CHARS); ?></h6>
<?php
foreach ($email->cc as $cc) {
print "<h6 class='card-subtitle text-muted'>CC: " . filter_var($cc, FILTER_SANITIZE_SPECIAL_CHARS) . "</h6>";
}
?>
<div class="mt-2 card-text">
<!-- TODO: switch between html and plaintext -->
<div>
<!-- TODO: applyAutolink
TODO: applyNewlines -->
<?php $text = filter_var($email->textPlain, FILTER_SANITIZE_SPECIAL_CHARS);
echo str_replace('&#10;', '<br />', $text);
?>
</div>
<div *ngIf="htmlTabActive">
<!-- TODO: stripHtml(mail.textHtml) -->
</div>
</div>
</div>
</div>
</div>
<?php
}
}
?>
</div>
</main>
</body>
</html>

View file

@ -19,22 +19,18 @@ div.min-height {
header {
background-color: #D9E2E9;
/* leave some space on top */
padding-top: 5px;
}
#openRandomButton {
/* center vertically */
margin-top: 6px;
}
.email-table > .email {
border-top: 5px solid #7C96AB;
/* idea: card shadow arround:
see https://blog.alexdevero.com/mastering-card-design-with-bootstrap-4/
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
*/
}
.header-shadow {
@ -47,7 +43,6 @@ header {
background-color: white;
}
.waiting-screen {
padding: 40px 15px;
text-align: center;
@ -57,3 +52,7 @@ div.min-height {
min-height: 400px;
}
.random-column {
border-left: 1px dashed #333;
}

6
src/turbolinks.js Normal file

File diff suppressed because one or more lines are too long