Skip to content

Commit e4af661

Browse files
authored
Merge pull request #7
PHPCoin Vanity Address Generator v0.0.1
2 parents 7d8be30 + 7824b8a commit e4af661

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

utils/vanitygen.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
3+
const VANITYGEN_NAME = 'PHPCoin Vanity Address Generator';
4+
const VANITYGEN_VERSION = '0.0.1';
5+
const VANITYGEN_USAGE = 'Usage: php vanitygen.php prefix [-c] [-d]' . PHP_EOL .
6+
' prefix Prefix for the PHPCoin address (e.g., "Php")' . PHP_EOL .
7+
' -c Case sensitive matching' . PHP_EOL .
8+
' -d Enable debug output' . PHP_EOL;
9+
const VANITYGEN_URL = 'https://github.com/phpcoinn/node/blob/main/utils/vanitygen.php';
10+
const DEFAULT_CHAIN_ID = '00';
11+
12+
$debug = false;
13+
14+
print VANITYGEN_NAME . ' v' . VANITYGEN_VERSION . PHP_EOL;
15+
16+
setupOrExit();
17+
18+
generateVanityAddress(getOptionsOrExit($argv));
19+
20+
print PHP_EOL . 'Exiting ' . VANITYGEN_NAME . PHP_EOL;
21+
22+
/**
23+
* Generates a vanity PHPCoin address based on the provided options.
24+
*
25+
* @param array $options An associative array with keys:
26+
* - 'prefix': The desired prefix for the address.
27+
* - 'case_sensitive': Boolean indicating if the match should be case sensitive.
28+
* @return array The generated account details containing 'address', 'public_key', and 'private_key'.
29+
*/
30+
function generateVanityAddress(array $options): array
31+
{
32+
$prefix = $options['prefix'];
33+
// All PHPCoin addresses start with uppercase 'P'
34+
if (! str_starts_with($prefix, 'p') && ! str_starts_with($prefix, 'P')) {
35+
$prefix = 'P' . $prefix;
36+
}
37+
// Force starting with uppercase 'P'
38+
if (str_starts_with($prefix, 'p')) {
39+
$prefix = 'P' . substr($prefix, 1);
40+
}
41+
42+
$caseSensitive = $options['case_sensitive'];
43+
44+
print 'Prefix: ' . $prefix . PHP_EOL;
45+
print 'Case Sensitive: ' . ($caseSensitive ? 'Yes' : 'No') . PHP_EOL;
46+
47+
$count = 0;
48+
49+
while (true) {
50+
$account = Account::generateAcccount();
51+
$address = $account['address'];
52+
$count++;
53+
_debug('Generation '. $count . ': ' . $address);
54+
55+
if (! $caseSensitive) {
56+
$address = strtolower($address);
57+
$prefix = strtolower($prefix);
58+
}
59+
if (str_starts_with($address, $prefix)) {
60+
print 'Found vanity PHPCoin address after '. $count . ' tries!' . PHP_EOL;
61+
print_r($account);
62+
return $account;
63+
}
64+
if ($count % 500 === 0) {
65+
print 'Generated ' . $count . ' PHPCoin addresses...' . PHP_EOL;
66+
}
67+
}
68+
}
69+
70+
/**
71+
* Parses command-line arguments into options and positional arguments.
72+
*
73+
* Supports:
74+
* - Positional arguments (e.g., "prefix")
75+
* - Long options (e.g., --foo)
76+
* - Long options with value (e.g., --value=foo or --value foo)
77+
* - Short options (e.g., -f)
78+
* - Short options with value (e.g., -v=foo or -v foo)
79+
*/
80+
function getOptionsOrExit(array $argv): array
81+
{
82+
global $debug;
83+
84+
$options = [];
85+
$arguments = [];
86+
87+
// Start at 1 to skip the script name ($argv[0])
88+
for ($i = 1; $i < count($argv); $i++) {
89+
$item = $argv[$i];
90+
if (strpos($item, '--') === 0) { // 1. Long Option: --key or --key=value or --key value
91+
$key = substr($item, 2);
92+
$value = true; // Default for flags like --verbose
93+
if (strpos($key, '=') !== false) { // Check for --key=value format
94+
list($key, $value) = explode('=', $key, 2);
95+
} else if (isset($argv[$i + 1]) && strpos($argv[$i + 1], '-') !== 0) {
96+
// Check for --key value format
97+
// Is there a next item? AND Is the next item NOT another option?
98+
$value = $argv[$i + 1];
99+
$i++; // Skip the next item, it's been consumed as a value
100+
}
101+
$options[$key] = $value;
102+
} else if (strpos($item, '-') === 0) { // 2. Short Option: -k or -k=value or -k value
103+
$key = substr($item, 1);
104+
$value = true; // Default for flags like -v
105+
// Check for -k=value format
106+
if (strpos($key, '=') !== false) {
107+
list($key, $value) = explode('=', $key, 2);
108+
}
109+
// Check for -k value format
110+
// Is there a next item? AND Is the next item NOT another option?
111+
else if (isset($argv[$i + 1]) && strpos($argv[$i + 1], '-') !== 0) {
112+
$value = $argv[$i + 1];
113+
$i++; // Skip the next item
114+
}
115+
$options[$key] = $value;
116+
} else { // 3. Positional Argument
117+
$arguments[] = $item;
118+
}
119+
}
120+
121+
if (empty($options) && empty($arguments)) {
122+
exit(VANITYGEN_USAGE . PHP_EOL);
123+
}
124+
125+
if (empty($arguments[0])) {
126+
exit('ERROR: No prefix provided.' . PHP_EOL . VANITYGEN_USAGE . PHP_EOL);
127+
}
128+
129+
if (isset($options['d'])) {
130+
$debug = true;
131+
}
132+
133+
return [
134+
'prefix' => $arguments[0],
135+
'case_sensitive' => isset($options['c']) ? true : false,
136+
];
137+
}
138+
139+
/**
140+
* Sets up the environment or exits if conditions are not met.
141+
*
142+
* Ensures the script is run from the command line and that the autoload file exists.
143+
*/
144+
function setupOrExit(): void
145+
{
146+
if (php_sapi_name() !== 'cli') {
147+
exit('ERROR: This script must be run from the command line' . PHP_EOL);
148+
};
149+
$autoload = Phar::running()
150+
? 'vendor/autoload.php'
151+
: dirname(__DIR__) . '/vendor/autoload.php';
152+
153+
if (! file_exists($autoload)) {
154+
exit('ERROR: Autoload file not found. Please run "composer install".' . PHP_EOL);
155+
}
156+
require_once $autoload;
157+
}
158+
159+
/**
160+
* Outputs debug messages if debugging is enabled.
161+
*
162+
* @param string $message The debug message to output.
163+
*/
164+
function _debug(string $message): void
165+
{
166+
global $debug;
167+
if ($debug) {
168+
print '[DEBUG] ' . $message . PHP_EOL;
169+
}
170+
}

0 commit comments

Comments
 (0)