├── JSONtoMYSQL
├── lib
│ ├── class.DatabaseException.php
│ ├── class.Timer.php
│ ├── class.HashTable.php
│ ├── class.MySQLResult.php
│ └── class.MySQLConn.php
├── class.JSONtoMYSQL.php
├── class.CreateMYSQLTable.php
├── class.AbstractMysqlTable.php
└── class.ExistingMYSQLTable.php
├── config-sample.php
├── example.php
├── .github
└── FUNDING.yml
├── README.md
├── include.classloader.php
└── LICENSE
/JSONtoMYSQL/lib/class.DatabaseException.php:
--------------------------------------------------------------------------------
1 | code}]: {$this->message}\n";
9 | }
10 | }
--------------------------------------------------------------------------------
/config-sample.php:
--------------------------------------------------------------------------------
1 | addToClasspath(ROOT);
11 |
12 |
13 | $mysql = new MySQLConn(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASS);
14 |
15 | $db = new JSONtoMYSQL($mysql);
16 |
17 | // create some json
18 | $obj = json_decode('{"id":4,"asdf" : "asfd"}');
19 |
20 | // save it to a table
21 | $db->save($obj, "brandnewtable");
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: adamwulf
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/lib/class.Timer.php:
--------------------------------------------------------------------------------
1 | start = false;
13 | $this->stop = false;
14 | }
15 |
16 | function start(): void
17 | {
18 | $this->start = (float)microtime(true);
19 | $this->stop = false;
20 | }
21 |
22 | function stop(): void
23 | {
24 | $this->stop = (float)microtime(true);
25 | }
26 |
27 | function read() : float{
28 | if(is_numeric($this->stop) &&
29 | is_numeric($this->start) &&
30 | ($this->stop > $this->start)){
31 | return ($this->stop - $this->start);
32 | }else
33 | if(is_numeric($this->start)){
34 | return (microtime(true) - $this->start);
35 | }else{
36 | return 0;
37 | }
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/lib/class.HashTable.php:
--------------------------------------------------------------------------------
1 | table = array();
11 | }
12 |
13 | function put($key, $obj): void
14 | {
15 | $this->table[$key] = $obj;
16 | }
17 |
18 | function get($key){
19 | if(isset($this->table[$key])){
20 | return $this->table[$key];
21 | }else{
22 | return false;
23 | }
24 | }
25 |
26 | function clear($key): void
27 | {
28 | if(isset($this->table[$key])){
29 | unset($this->table[$key]);
30 | }
31 | }
32 |
33 | function reset(): void
34 | {
35 | $this->table = array();
36 | }
37 |
38 |
39 | function enum(): array
40 | {
41 | $ret = [];
42 | foreach($this->table as $key => $item){
43 | $ret[] = $item;
44 | }
45 | return $ret;
46 | }
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | json-to-mysql
2 | =============
3 |
4 | Easily take any JSON object and create+insert it into a mysql table built from its structure. Also search, update, index, and validate tables with JSON.
5 |
6 | ```
7 |
8 | include("config.php");
9 | include("include.classloader.php");
10 |
11 | $classLoader->addToClasspath(ROOT);
12 |
13 |
14 | $mysql = new MySQLConn(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASS);
15 |
16 | $db = new JSONtoMYSQL($mysql);
17 |
18 | // create some json
19 | $obj = json_decode('{"id":4,"name" : "asfd"}');
20 |
21 | // save it to a table
22 | $db->save($obj, "brandnewtable");
23 |
24 | // SELECT * from brandnewtable WHERE id = 4
25 |
26 | $obj = $db->table("brandnewtable")->find(["id" => 4]);
27 |
28 | print_r($obj);
29 |
30 | // SELECT * FROM brandnewtable WHERE id > 4 ORDER BY name DESC
31 |
32 | $obj = $db->table("brandnewtable")->find(["id" => 4], ["id" => ">"], ["name DESC"]);
33 |
34 | print_r($obj);
35 |
36 | // SELECT * FROM brandnewtable WHERE id IN (4, 5, 6, 7)
37 |
38 | $obj = $db->table("brandnewtable")->find(["id" => [4, 5, 6, 7]]);
39 |
40 | print_r($obj);
41 |
42 |
43 | ```
44 |
45 | ## Support the project
46 |
47 | Has json-to-mysql saved you some time? Become a [Github Sponsor](https://github.com/sponsors/adamwulf) and buy me a coffee ☕️ 😄
48 |
49 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/lib/class.MySQLResult.php:
--------------------------------------------------------------------------------
1 | result = $result;
15 | $this->insert_id = @mysqli_insert_id($link);
16 | $this->affected_rows = @mysqli_affected_rows($link);
17 | $this->offset = 0;
18 | }
19 |
20 |
21 | function num_rows() : int {
22 | return mysqli_num_rows($this->result);
23 | }
24 |
25 | function fetch_array() : ?array {
26 | if($this->offset < $this->num_rows()){
27 | $this->offset += 1;
28 | return mysqli_fetch_array($this->result, MYSQLI_ASSOC);
29 | }
30 | return null;
31 | }
32 |
33 | function peek_array() : ?array {
34 | $offset = $this->offset;
35 | $ret = $this->fetch_array();
36 |
37 | if($this->offset != $offset){
38 | // restore pointer to previous record
39 | mysqli_data_seek($this->result, $offset);
40 | $this->offset = $offset;
41 | }
42 |
43 | return $ret;
44 | }
45 |
46 | function insert_id() : int {
47 | return $this->insert_id;
48 | }
49 |
50 | function affected_rows() : int {
51 | return $this->affected_rows;
52 | }
53 |
54 | function has_next() : bool {
55 | if($this->offset < $this->num_rows()){
56 | return true;
57 | }else{
58 | return false;
59 | }
60 | }
61 |
62 | function rewind() : bool {
63 | if($this->num_rows() > 0){
64 | $this->offset = 0;
65 | return mysqli_data_seek($this->result, 0);
66 | }
67 | return false;
68 | }
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/class.JSONtoMYSQL.php:
--------------------------------------------------------------------------------
1 | mysql = $mysql;
17 | $this->table_cache = [];
18 | }
19 |
20 |
21 | /**
22 | * will return the modifications needed
23 | * to the scheme to support inserting
24 | * the input json object
25 | *
26 | * returns an array of modifications
27 | * including:
28 | * creating tables
29 | * adding columns
30 | * modifying existing columns
31 | * adding foreign keys / foreign tables
32 | * flattening sub object into columns
33 | * @throws DatabaseException
34 | */
35 | public function save($json_obj, $tablename): MySQLResult
36 | {
37 | $table = $this->table($tablename);
38 | $table->validateTableFor($json_obj);
39 | return $table->save($json_obj);
40 | }
41 |
42 | /**
43 | * create or return a table for the input
44 | * tablename
45 | * @throws DatabaseException
46 | */
47 | public function table($tablename){
48 | if($this->tableExistsHuh($tablename)){
49 | return new ExistingMYSQLTable($this->mysql, $tablename);
50 | }else if(isset($this->table_cache[$tablename])){
51 | return $this->table_cache[$tablename];
52 | } else {
53 | $this->table_cache[$tablename] = new CreateMYSQLTable($this->mysql, $tablename);
54 | return $this->table_cache[$tablename];
55 | }
56 | }
57 |
58 | /**
59 | * helper method to determine if a table
60 | * already exists
61 | * @throws DatabaseException
62 | */
63 | protected function tableExistsHuh($tablename): bool
64 | {
65 | $sql = "SHOW TABLES LIKE '" . addslashes($tablename) . "'";
66 | $result = $this->mysql->query($sql);
67 | return $result->num_rows() > 0;
68 | }
69 |
70 | public function mysql() : MySQLConn{
71 | return $this->mysql;
72 | }
73 | }
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/class.CreateMYSQLTable.php:
--------------------------------------------------------------------------------
1 | isLocked()){
20 | throw new DatabaseException("JsonToMysql is locked. Cannot create new table " . $this->tablename);
21 | }
22 |
23 | $colstr = "";
24 |
25 | foreach($data as $key => $value){
26 | if(is_array($value)){
27 | echo "need to handle array subdata\n";
28 | }else if(is_object($value)){
29 | echo "need to handle object subdata\n";
30 | }else if($key != $this->primary){
31 | $colname = $this->getColumnNameForKey($key);
32 | $type = $this->getMysqlTypeForValue($value);
33 | $nullable = false;
34 |
35 | if($typeForColName){
36 | $typeInfo = $typeForColName($colname, $value, $type);
37 | if(is_array($typeInfo)){
38 | $type = $typeInfo[0];
39 | $nullable = $typeInfo[1];
40 | }else{
41 | $type = $typeInfo;
42 | }
43 | }
44 |
45 | if(!$type){
46 | /** @noinspection ForgottenDebugOutputInspection */
47 | error_log(" - unknown type for column " . $colname);
48 | }
49 |
50 | $nullability = $nullable ? " NULL " : " NOT NULL ";
51 |
52 | $colstr .= " `" . $colname . "` " . $type . $nullability . ",";
53 | }
54 | }
55 |
56 |
57 | $sql = "CREATE TABLE IF NOT EXISTS `" . addslashes($this->tablename) . "` ("
58 | . " `" . $this->primary . "` bigint(20) NOT NULL auto_increment,"
59 | . $colstr
60 | . " PRIMARY KEY (`" . $this->primary . "`)"
61 | . ") ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;";
62 |
63 | $this->mysql->query($sql);
64 |
65 | $issues = [];
66 | $issues[] = ["notice" => "created table"];
67 | return $issues;
68 | }
69 |
70 | /**
71 | * returns a MysqlResult for a SELECT query
72 | * that tries to find all values in the table
73 | * that match the input json object
74 | * @throws DatabaseException
75 | */
76 | public function find($json_obj = array(), $ops=false, $orders=false) : MySQLResult{
77 | $sql = "SELECT 0 LIMIT 0";
78 | return $this->mysql->query($sql);
79 | }
80 |
81 | /**
82 | * @param $json_obj
83 | * @return MySQLResult
84 | * @throws DatabaseException
85 | */
86 | public function delete($json_obj) : MySQLResult{
87 | $sql = "SELECT 0 LIMIT 0";
88 | return $this->mysql->query($sql);
89 | }
90 |
91 | /**
92 | * @return MySQLResult
93 | * @throws DatabaseException
94 | */
95 | public function truncate() : MySQLResult{
96 | $sql = "SELECT 0 LIMIT 0";
97 | return $this->mysql->query($sql);
98 | }
99 |
100 |
101 | public function addUniqueIndexTo(array $columns, string $name): void{
102 | // noop
103 | }
104 |
105 | public function addIndexTo(array $columns, string $name) : void{
106 | // noop
107 | }
108 |
109 | }
110 |
111 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/class.AbstractMysqlTable.php:
--------------------------------------------------------------------------------
1 | mysql = $mysql;
34 | $this->tablename = $tablename;
35 | $this->primary = $this->getColumnNameForKey($primary);
36 | $this->locked = JSONTOMYSQL_LOCKED;
37 | }
38 |
39 | public function isLocked(): bool
40 | {
41 | return $this->locked;
42 | }
43 |
44 | public function setLocked(bool $lock): void
45 | {
46 | $this->locked = $lock;
47 | }
48 |
49 | public function name(): string
50 | {
51 | return $this->tablename;
52 | }
53 |
54 | abstract public function primaryColumn();
55 |
56 | /**
57 | * this method should be called to make sure that
58 | * the table exists and could operate on the input
59 | * data if needed
60 | *
61 | * this will create the table if needed, and will create
62 | * any columns necessary for existing tables
63 | *
64 | * $typeForColName($data, $value) can return a mysql data type
65 | * to override JSONtoMYSQL's auto type.
66 | */
67 | abstract public function validateTableFor($json_data, Closure $typeForColName = null);
68 |
69 | /**
70 | * will insert or update the table for the input
71 | * json object. the row will update if the input
72 | * does match a value in the primary column, otherwise
73 | * will insert a new row
74 | */
75 | abstract public function save($json_data) : MySQLResult;
76 |
77 | abstract public function update($json_data) : MySQLResult;
78 |
79 | abstract public function insert($json_data) : MySQLResult;
80 |
81 | abstract public function find(array $json_obj = array(), array $ops = null, array $orders = null) : MySQLResult;
82 |
83 | abstract public function delete($json_obj) : MySQLResult;
84 |
85 | abstract public function truncate() : MySQLResult;
86 |
87 | abstract public function addUniqueIndexTo(array $columns, string $name): void;
88 |
89 | abstract public function addIndexTo(array $columns, string $name) : void;
90 |
91 | /**
92 | * helper method to make a mysql safe column name
93 | * from any input string
94 | */
95 | public function getColumnNameForKey(string $key) : string {
96 | return preg_replace('/[^a-zA-Z0-9_]/', '', $key);
97 | }
98 |
99 | /**
100 | * will determine a valid mysql column type from
101 | * the input variable value
102 | * @param mixed $val
103 | * @return string
104 | * @throws DatabaseException
105 | */
106 | protected function getMysqlTypeForValue($val) : ?string {
107 | if(preg_match('/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $val)){
108 | return "DATETIME";
109 | }else if(preg_match('/\d{4}-\d{2}-\d{2}/', $val)){
110 | return "DATE";
111 | }else if(is_string($val)){
112 | return "TEXT";
113 | }else if(is_bool($val)){
114 | return "TINYINT";
115 | }else if(is_int($val)){
116 | return "BIGINT";
117 | }else if(is_double($val) || is_float($val) || is_real($val)){
118 | return "DOUBLE";
119 | }else if(!is_null($val)){
120 | throw new DatabaseException("unknown mysql type for: " . gettype($val));
121 | }
122 | return null;
123 | }
124 | }
125 |
126 |
127 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/lib/class.MySQLConn.php:
--------------------------------------------------------------------------------
1 | host = $h;
30 | $this->database = $db;
31 | $this->user = $u;
32 | $this->pass = $p;
33 | $this->_query_count = 0;
34 | $this->_mysqli_link = false;
35 | $this->_query_cache = new HashTable();
36 | $this->logger = $log;
37 | }
38 |
39 | /**
40 | * queries mysql and caches the result if appropriate
41 | * @param $sql
42 | * @param bool $verbose
43 | * @return MySQLResult
44 | * @throws DatabaseException
45 | */
46 | function query($sql, $verbose=false) : MySQLResult{
47 | $sql = trim($sql);
48 | if($this->_mysqli_link === false){
49 | $this->_mysqli_link = mysqli_connect($this->host, $this->user, $this->pass, $this->database);
50 | mysqli_set_charset($this->_mysqli_link, "utf8");
51 | }
52 | if($this->_mysqli_link === false){
53 | throw new DatabaseException("could not connect to MySQL");
54 | }
55 |
56 | if($this->_query_cache->get($sql)){
57 | if($verbose)echo "found in cache
";
58 | $result = $this->_query_cache->get($sql);
59 | if(mysqli_num_rows($result)){
60 | if($verbose) echo ": seeking to 0";
61 | mysqli_data_seek($result, 0);
62 | }
63 | $ret = new MySQLResult($this->_mysqli_link, $result);
64 | if($verbose) echo "
";
65 | }else{
66 | if($verbose) echo "not in cache";
67 | $this->_query_count++;
68 | /**
69 | * this following line should be run once per connection to mysql
70 | *
71 | * i'm running it before every query. I can probably optimize this
72 | * to run once per connection, but I need to do some thorough testing...
73 | *
74 | * http://dev.mysql.com/doc/refman/5.6/en/charset-connection.html
75 | */
76 | if(is_object($this->logger)){
77 | $this->logger->log($this, ALogger::$LOW, $sql);
78 | }
79 |
80 | mysqli_set_charset($this->_mysqli_link, "utf8");
81 | $timer = new Timer();
82 | $timer->start();
83 | $result = mysqli_query($this->_mysqli_link, $sql);
84 | $ret = new MySQLResult($this->_mysqli_link, $result);
85 | $timer->stop();
86 | $time = $timer->read();
87 |
88 | /**
89 | * the query is too long! oh noes!
90 | */
91 | if($time > .1){
92 | /**
93 | * save the query to the DB, so I can look at it later
94 | */
95 | error_log("long query: " . $sql);
96 | if(is_object($this->logger)){
97 | $this->logger->longQuery($time, $sql);
98 | }
99 | }
100 |
101 | if(mysqli_error($this->_mysqli_link)){
102 | if($verbose) echo "mysqli_error: " . mysqli_error($this->_mysqli_link) . "
";
103 | error_log("sql error: " . $sql);
104 | throw new DatabaseException(mysqli_error($this->_mysqli_link));
105 | }
106 | if(strpos($sql, "SELECT") === 0){
107 | if($verbose) echo ": select: $sql
";
108 | $this->_query_cache->put($sql, $result);
109 | }else{
110 | if($verbose) echo ": not select: $sql
";
111 | if($verbose) echo "clearing cache
";
112 | $this->_query_cache->reset();
113 | }
114 |
115 | }
116 | return $ret;
117 | }
118 |
119 | function reset() : void{
120 | $this->_query_count = 0;
121 | $this->_query_cache->reset();
122 | }
123 |
124 | function getQueryCount() : int{
125 | return $this->_query_count;
126 | }
127 |
128 | function close() : bool{
129 | if(!is_bool($this->_mysqli_link)){
130 | return @mysqli_close($this->_mysqli_link);
131 | }else{
132 | return false;
133 | }
134 | }
135 |
136 | }
137 |
138 |
139 |
--------------------------------------------------------------------------------
/include.classloader.php:
--------------------------------------------------------------------------------
1 | classpath = array();
12 | }
13 |
14 | /**
15 | * @param $dir
16 | * @throws Exception
17 | */
18 | public function addToClasspath($dir) : void{
19 | if(is_dir($dir)){
20 | $this->classpath[] = $dir;
21 | }else{
22 | throw new Exception("cannot find directory: $dir");
23 | }
24 | }
25 |
26 | /**
27 | * @param $classname
28 | * @return bool
29 | */
30 | public function load($classname) : bool{
31 | $ok = false;
32 | foreach ($this->classpath as $path) {
33 | /* echo "load recur \"" . $path . "\";//
\n"; */
34 | $ok = $ok || $this->load_recursive($path, $classname);
35 | }
36 | return $ok;
37 | }
38 |
39 | protected function load_recursive($classpath, $classname) : bool{
40 | $ret = false;
41 | if ($handle = opendir($classpath)) {
42 | while (false != ($file = readdir($handle))) {
43 | if ($file != "." && $file != "..") {
44 | if(is_dir($classpath . $file)){
45 | $ret = $ret || $this->load_recursive($classpath . $file . "/", $classname);
46 | }else{
47 | if($file == "class.$classname.php"){
48 | include_once $classpath . $file;
49 | $ret = true;
50 | /* echo "include_once \"" . $classpath . $file . "\";//
\n"; */
51 | }else
52 | if($file == "class.Boolean.$classname.php"){
53 | include_once $classpath . $file;
54 | $ret = true;
55 | /* echo "include_once \"" . $classpath . $file . "\";//
\n"; */
56 | }else
57 | if($file == "interface.$classname.php"){
58 | include_once $classpath . $file;
59 | $ret = true;
60 | /* echo "include_once \"" . $classpath . $file . "\";//
\n"; */
61 | }else
62 | if($file == "abstract.$classname.php"){
63 | include_once $classpath . $file;
64 | $ret = true;
65 | /* echo "include_once \"" . $classpath . $file . "\";//
\n"; */
66 | }
67 | }
68 | }
69 | }
70 | closedir($handle);
71 | unset($handle);
72 | }
73 | return $ret;
74 | }
75 | }
76 |
77 | class ClassLoaderToString extends ClassLoader{
78 |
79 | protected function load_recursive($classpath, $classname) : bool{
80 | $ret = false;
81 | if ($handle = opendir($classpath)) {
82 | while (false != ($file = readdir($handle))) {
83 | if ($file != "." && $file != "..") {
84 | if(is_dir($classpath . $file)){
85 | $this->load_recursive($classpath . $file . "/", $classname);
86 | }else{
87 | if($file == "class.$classname.php"){
88 | include_once $classpath . $file;
89 | $this->printClass($classpath, $file);
90 | $ret = true;
91 | }else
92 | if($file == "class.Boolean.$classname.php"){
93 | include_once $classpath . $file;
94 | $this->printClass($classpath, $file);
95 | $ret = true;
96 | }else
97 | if($file == "interface.$classname.php"){
98 | include_once $classpath . $file;
99 | $this->printClass($classpath, $file);
100 | $ret = true;
101 | }
102 | }
103 | }
104 | }
105 | closedir($handle);
106 | unset($handle);
107 | }
108 | return $ret;
109 | }
110 |
111 | protected function printClass($classpath, $file) : void{
112 | if(strpos($classpath, ROOT) === 0){
113 | $classpath = substr($classpath, strlen(ROOT));
114 | echo "include_once(ROOT . \"" . $classpath . $file . "\");\n";
115 | }else{
116 | echo "include_once(\"" . $classpath . $file . "\");\n";
117 | }
118 | }
119 | }
120 |
121 |
122 | function milestone_autoload($classname){
123 | global $classLoader;
124 | // global $control;
125 | // $str = "classname: ";
126 | // $str .= $classname;
127 | // $str .= "\n";
128 | // if(is_object($control) && !is_int(stripos($classname, "mysql"))){
129 | // $control->getModel()->getLogger()->log($control->getModel(), ALogger::$HIGH, $str);
130 | // }
131 | try{
132 | $classLoader->load($classname);
133 | // $str .= ":" . $ok;
134 | // if(is_object($control) && !is_int(stripos($classname, "mysql"))){
135 | // $control->getModel()->getLogger()->log($control->getModel(), ALogger::$HIGH, $str);
136 | // }
137 | }catch(Exception $e){
138 | /** @noinspection ForgottenDebugOutputInspection */
139 | error_log($e->getMessage());
140 | // $model->getLogger()->log($model, ALogger::$HIGH, print_r($e, true));
141 | }
142 | }
143 |
144 | spl_autoload_register('milestone_autoload');
145 |
146 | $classLoader = new ClassLoader();
147 |
--------------------------------------------------------------------------------
/JSONtoMYSQL/class.ExistingMYSQLTable.php:
--------------------------------------------------------------------------------
1 | fields = array();
16 | }
17 |
18 | public function primaryColumn() : string {
19 | return $this->primary;
20 | }
21 |
22 | /**
23 | * make sure to cache our primary column name
24 | * to ease future operations
25 | * @throws DatabaseException
26 | */
27 | public function validateTableFor($data, Closure $typeForColName = null, Closure $nullabilityForColName = null) : array {
28 | $issues = [];
29 |
30 | if(!count($this->fields)){
31 | // pull the primary column from the database
32 | $sql = "show index from " . addslashes($this->tablename) . " where Key_name = 'PRIMARY' ;";
33 | $result = $this->mysql->query($sql);
34 | $arr = $result->fetch_array();
35 | $this->primary = $arr["Column_name"];
36 |
37 | // fetch all columns and types
38 | $this->fields = array();
39 | $sql = "SHOW FIELDS FROM `" . addslashes($this->tablename) . "`";
40 | $result = $this->mysql->query($sql);
41 | while($row = $result->fetch_array()){
42 | $field = array("name" => $row["Field"], "type" => $row["Type"], "nullable" => $row["Null"] == "YES");
43 | $this->fields[] = $field;
44 | }
45 | }
46 |
47 | $missing = array();
48 | foreach($data as $key => $value){
49 | if(!is_array($value) && !is_object($value)){
50 | $columnname = $this->getColumnNameForKey($key);
51 | $found = false;
52 | foreach($this->fields as $field){
53 | if($field["name"] == $columnname){
54 | $found = $field;
55 | break;
56 | }
57 | }
58 | $type = $this->getMysqlTypeForValue($value);
59 | $nullable = null;
60 |
61 | if($typeForColName){
62 | $typeInfo = $typeForColName($columnname, $value, $type);
63 | if(is_array($typeInfo)){
64 | $type = $typeInfo[0];
65 | $nullable = $typeInfo[1];
66 | }else{
67 | $type = $typeInfo;
68 | }
69 | }
70 |
71 | if(!$type && !$found){
72 | $issues[] = ["column" => $columnname, "error" => "unknown type"];
73 | /** @noinspection ForgottenDebugOutputInspection */
74 | error_log(" - unknown type for column " . $columnname . " when validating table " . $this->name());
75 | }
76 |
77 | if(!$found){
78 | $issues[] = ["column" => $columnname, "error" => "missing column " . $type . " null? " . $nullable];
79 | $missing[] = array("name" => $columnname, "type" => $type, "nullable" => $nullable);
80 | }else{
81 | $type = strtoupper($type);
82 | $foundType = strtoupper($found["type"]);
83 | if($type && $foundType && strpos($type, $foundType) !== 0 && strpos($foundType, $type) !== 0){
84 | $issues[] = ["column" => $columnname, "error" => "invalid type: should be " . $type . ", but is " . $found["type"]];
85 | }
86 | if($nullable && !$found["nullable"]){
87 | $issues[] = ["column" => $columnname, "error" => "invalid nullability: should nullable, but isn't"];
88 | }else if($nullable === false && $found["nullable"]){
89 | $issues[] = ["column" => $columnname, "error" => "invalid nullability: shouldn't nullable, but is"];
90 | }
91 | }
92 | }
93 | }
94 |
95 | if($this->isLocked() && count($missing)){
96 | $colnames = array_map(function($field){
97 | return $field["name"];
98 | }, $missing);
99 | throw new DatabaseException("JsonToMysql is locked. Cannot create columns " . join(',', $colnames) . " in table " . $this->tablename);
100 | }else if(count($missing)){
101 | foreach($missing as $field){
102 | $nullability = $field["nullable"] ? " NULL " : " NOT NULL ";
103 | $sql = "ALTER TABLE `" . addslashes($this->tablename) . "` ADD `" . addslashes($field["name"]) . "` " . $field["type"] . $nullability . ";";
104 | $this->mysql->query($sql);
105 | $this->fields[] = $field;
106 | }
107 | }
108 |
109 | return $issues;
110 | }
111 |
112 |
113 | /**
114 | * @param array $columns
115 | * @param string $name
116 | * @throws DatabaseException
117 | */
118 | public function addUniqueIndexTo(array $columns, string $name) : void {
119 | $sql = "show index from " . addslashes($this->tablename) . " where Key_name = '" . addslashes($name) . "' ;";
120 | $result = $this->mysql->query($sql);
121 |
122 | if(!$result->num_rows()){
123 |
124 | $cols = "";
125 | foreach($columns as $column){
126 | if(strlen($cols)){
127 | $cols .= ", ";
128 | }
129 | if(is_string($column)){
130 | $cols .= "`" . addslashes($column) . "`";
131 | }else if(is_array($column)){
132 | $cols .= "`" . addslashes($column[0]) . "`(" . ((int)$column[1]) . ")";
133 | }
134 | }
135 |
136 | $sql = "ALTER TABLE `" . addslashes($this->tablename) . "` ADD UNIQUE `" . addslashes($name) . "` (" . $cols . ");";
137 | $this->mysql->query($sql);
138 | }
139 | }
140 |
141 | /**
142 | * @param array $columns
143 | * @param string $name
144 | * @throws DatabaseException
145 | */
146 | public function addIndexTo(array $columns, string $name) : void {
147 | $sql = "show index from " . addslashes($this->tablename) . " where Key_name = '" . addslashes($name) . "' ;";
148 | $result = $this->mysql->query($sql);
149 |
150 | if(!$result->num_rows()){
151 |
152 | $cols = "";
153 | foreach($columns as $column){
154 | if(strlen($cols)){
155 | $cols .= ", ";
156 | }
157 | if(is_string($column)){
158 | $cols .= "`" . addslashes($column) . "`";
159 | }else if(is_array($column)){
160 | $cols .= "`" . addslashes($column[0]) . "`(" . ((int)$column[1]) . ")";
161 | }
162 | }
163 |
164 | $sql = "ALTER TABLE `" . addslashes($this->tablename) . "` ADD INDEX `" . addslashes($name) . "` (" . $cols . ");";
165 | $this->mysql->query($sql);
166 | }
167 | }
168 |
169 |
170 | /**
171 | * will save the input json object contains
172 | * a value for the primary column or will
173 | * insert a new row
174 | * @throws DatabaseException
175 | */
176 | public function save($json_obj) : MySQLResult{
177 | $this->validateTableFor($json_obj);
178 | $primary = $this->primary;
179 |
180 | $primary_value = false;
181 | if(is_array($json_obj) && isset($json_obj[$primary])){
182 | $primary_value = $json_obj[$primary];
183 | }else if(is_object($json_obj) && isset($json_obj->$primary)){
184 | $primary_value = $json_obj->$primary;
185 | }
186 |
187 | if($primary_value){
188 | $res = $this->find(array($primary => $primary_value));
189 | if($res->num_rows()){
190 | // already exists with this primary key value, update it
191 | return $this->update($json_obj);
192 | }else{
193 | // doesn't exist yet, insert
194 | return $this->insert($json_obj);
195 | }
196 | }else{
197 | return $this->insert($json_obj);
198 | }
199 | }
200 |
201 |
202 | /**
203 | * returns a MysqlResult for a SELECT query
204 | * that tries to find all values in the table
205 | * that match the input json object
206 | * @throws DatabaseException
207 | */
208 | public function find(array $json_obj = array(), array $ops = null, array $orders = null) : MySQLResult{
209 | $this->validateTableFor($json_obj);
210 | $where = "";
211 | foreach ($json_obj as $key => $value) {
212 | if (is_array($value)) {
213 | $colname = $this->getColumnNameForKey($key);
214 | if (strlen($where)) {
215 | $where .= " AND ";
216 | }
217 | $where .= "`" . $colname . "`";
218 | $op = ($ops && $ops[$key]) ? addslashes($ops[$key]) : "IN";
219 | $where .= " $op (";
220 | $idx = 0;
221 | foreach ($value as $val) {
222 | $where .= ($idx ? "," : "") . "'" . addslashes($val) . "'";
223 | $idx++;
224 | }
225 | $where .= ") ";
226 | } else if (is_object($value)) {
227 | /* echo "need to handle object subdata\n"; */
228 | } else {
229 | $colname = $this->getColumnNameForKey($key);
230 | if (strlen($where)) {
231 | $where .= " AND ";
232 | }
233 | $where .= "`" . $colname . "`";
234 | if ($this->getMysqlTypeForValue($value) == "TEXT") {
235 | $op = ($ops && $ops[$key]) ? addslashes($ops[$key]) : "LIKE";
236 | $where .= " $op '" . addslashes($value) . "'";
237 | } else {
238 | $op = ($ops && $ops[$key]) ? addslashes($ops[$key]) : "=";
239 | $where .= " $op '" . addslashes($value) . "'";
240 | }
241 | }
242 | }
243 | $sql = "SELECT * FROM `" . addslashes($this->tablename);
244 | if ($where) {
245 | $sql .= "` WHERE " . $where;
246 | } else {
247 | $sql .= "`";
248 | }
249 |
250 | if (is_array($orders) && count($orders)) {
251 | $sql .= " ORDER BY ";
252 |
253 | foreach ($orders as $i => $order) {
254 | $sql .= addslashes($order);
255 | if ($i < count($orders) - 1) {
256 | $sql .= ", ";
257 | }
258 | }
259 | }
260 |
261 | return $this->mysql->query($sql);
262 | }
263 |
264 | /**
265 | * finds the rows just like the find() method
266 | * and then deletes all of them
267 | * @throws DatabaseException
268 | */
269 | public function delete($json_obj) : MySQLResult{
270 | $where = "";
271 |
272 | foreach($json_obj as $key => $value){
273 | if(is_array($value)){
274 | /* echo "need to handle array subdata\n"; */
275 | }else if(is_object($value)){
276 | /* echo "need to handle object subdata\n"; */
277 | }else{
278 | $colname = $this->getColumnNameForKey($key);
279 | if(strlen($where)){
280 | $where .= " AND ";
281 | }
282 | $where .= "`" . $colname . "`";
283 | if($this->getMysqlTypeForValue($value) == "TEXT"){
284 | $where .= " LIKE '" . addslashes($value) . "'";
285 | }else{
286 | $where .= " = '" . addslashes($value) . "'";
287 | }
288 | }
289 | }
290 | if(strlen($where)){
291 | $sql = "DELETE FROM `" . addslashes($this->tablename) . "` WHERE " . $where;
292 |
293 | return $this->mysql->query($sql);
294 | }else{
295 | $sql = "SELECT 0 LIMIT 0";
296 | return $this->mysql->query($sql);
297 | }
298 | }
299 |
300 | /**
301 | * finds the rows just like the find() method
302 | * and then deletes all of them
303 | * @throws DatabaseException
304 | */
305 | public function truncate() : MySQLResult{
306 | $sql = "TRUNCATE `" . addslashes($this->tablename) . "`";
307 | return $this->mysql->query($sql);
308 | }
309 |
310 | /**
311 | * will update a row in the database for
312 | * the input object by comparing its value
313 | * for the primary column name
314 | * @throws DatabaseException
315 | */
316 | public function update($json_obj) : MySQLResult{
317 | $this->validateTableFor($json_obj);
318 | $set = "";
319 |
320 | $primary_val = 0;
321 |
322 | foreach($json_obj as $key => $value){
323 | if($key == $this->primary){
324 | $primary_val = $value;
325 | continue;
326 | }
327 | if(is_array($value)){
328 | /* echo "need to handle array subdata\n"; */
329 | }else if(is_object($value)){
330 | /* echo "need to handle object subdata\n"; */
331 | }else{
332 | $colname = $this->getColumnNameForKey($key);
333 | if(strlen($set)){
334 | $set .= ", ";
335 | }
336 | $set .= "`" . $colname . "`";
337 |
338 | if(is_bool($value)){
339 | $value = (int)$value;
340 | }
341 |
342 | if(is_null($value)){
343 | $set .= " = NULL";
344 | }else{
345 | $set .= " = '" . addslashes($value) . "'";
346 | }
347 | }
348 | }
349 | if(strlen($set)){
350 | $sql = "UPDATE `" . addslashes($this->tablename) . "` SET "
351 | . $set . " WHERE `" . $this->primary . "`='" . addslashes($primary_val) . "';";
352 |
353 | return $this->mysql->query($sql);
354 | }else{
355 | $sql = "SELECT 0 LIMIT 0";
356 | return $this->mysql->query($sql);
357 | }
358 | }
359 |
360 | /**
361 | * this method will attempt to add a new row
362 | * to the table with all of the values
363 | * of the input json object
364 | * @throws DatabaseException
365 | */
366 | public function insert($json_obj) : MySQLResult{
367 | $this->validateTableFor($json_obj);
368 | $fields = "";
369 | $values = "";
370 |
371 | foreach($json_obj as $key => $value){
372 | if(is_array($value)){
373 | /* echo "need to handle array subdata\n"; */
374 | }else if(is_object($value)){
375 | /* echo "need to handle object subdata\n"; */
376 | }else{
377 | $colname = $this->getColumnNameForKey($key);
378 | if(strlen($fields)){
379 | $fields .= ",";
380 | $values .= ",";
381 | }
382 | $fields .= "`" . $colname . "`";
383 |
384 | if(is_bool($value)){
385 | $value = (int)$value;
386 | }
387 |
388 | if(is_null($value)){
389 | $values .= "NULL";
390 | }else{
391 | $values .= "'" . addslashes($value) . "'";
392 | }
393 | }
394 | }
395 |
396 | if(strlen($fields)){
397 | $sql = "INSERT INTO `" . addslashes($this->tablename) . "` "
398 | . "(" . $fields . ") VALUES (" . $values . ")";
399 |
400 | return $this->mysql->query($sql);
401 | }else{
402 | $sql = "SELECT 0 LIMIT 0";
403 | return $this->mysql->query($sql);
404 | }
405 | }
406 |
407 | /**
408 | * returns true if the input column name already exists
409 | * in the table, or false otherwise
410 | * @throws DatabaseException
411 | */
412 | protected function columnExistsInTableHuh($columnname) : bool {
413 | if(count($this->fields)){
414 | foreach($this->fields as $field){
415 | if($field["name"] == $columnname){
416 | return true;
417 | }
418 | }
419 | return false;
420 | }
421 | $sql = "SHOW COLUMNS FROM `" . addslashes($this->tablename) . "` LIKE '" . addslashes($columnname) . "'";
422 | $result = $this->mysql->query($sql);
423 | return $result->num_rows() > 0;
424 | }
425 |
426 |
427 |
428 | }
429 |
430 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | Attribution 3.0 Unported
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
10 | DAMAGES RESULTING FROM ITS USE.
11 |
12 | License
13 |
14 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
15 | COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
16 | COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
17 | AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
18 |
19 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
20 | TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
21 | BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
22 | CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
23 | CONDITIONS.
24 |
25 | 1. Definitions
26 |
27 | a. "Adaptation" means a work based upon the Work, or upon the Work and
28 | other pre-existing works, such as a translation, adaptation,
29 | derivative work, arrangement of music or other alterations of a
30 | literary or artistic work, or phonogram or performance and includes
31 | cinematographic adaptations or any other form in which the Work may be
32 | recast, transformed, or adapted including in any form recognizably
33 | derived from the original, except that a work that constitutes a
34 | Collection will not be considered an Adaptation for the purpose of
35 | this License. For the avoidance of doubt, where the Work is a musical
36 | work, performance or phonogram, the synchronization of the Work in
37 | timed-relation with a moving image ("synching") will be considered an
38 | Adaptation for the purpose of this License.
39 | b. "Collection" means a collection of literary or artistic works, such as
40 | encyclopedias and anthologies, or performances, phonograms or
41 | broadcasts, or other works or subject matter other than works listed
42 | in Section 1(f) below, which, by reason of the selection and
43 | arrangement of their contents, constitute intellectual creations, in
44 | which the Work is included in its entirety in unmodified form along
45 | with one or more other contributions, each constituting separate and
46 | independent works in themselves, which together are assembled into a
47 | collective whole. A work that constitutes a Collection will not be
48 | considered an Adaptation (as defined above) for the purposes of this
49 | License.
50 | c. "Distribute" means to make available to the public the original and
51 | copies of the Work or Adaptation, as appropriate, through sale or
52 | other transfer of ownership.
53 | d. "Licensor" means the individual, individuals, entity or entities that
54 | offer(s) the Work under the terms of this License.
55 | e. "Original Author" means, in the case of a literary or artistic work,
56 | the individual, individuals, entity or entities who created the Work
57 | or if no individual or entity can be identified, the publisher; and in
58 | addition (i) in the case of a performance the actors, singers,
59 | musicians, dancers, and other persons who act, sing, deliver, declaim,
60 | play in, interpret or otherwise perform literary or artistic works or
61 | expressions of folklore; (ii) in the case of a phonogram the producer
62 | being the person or legal entity who first fixes the sounds of a
63 | performance or other sounds; and, (iii) in the case of broadcasts, the
64 | organization that transmits the broadcast.
65 | f. "Work" means the literary and/or artistic work offered under the terms
66 | of this License including without limitation any production in the
67 | literary, scientific and artistic domain, whatever may be the mode or
68 | form of its expression including digital form, such as a book,
69 | pamphlet and other writing; a lecture, address, sermon or other work
70 | of the same nature; a dramatic or dramatico-musical work; a
71 | choreographic work or entertainment in dumb show; a musical
72 | composition with or without words; a cinematographic work to which are
73 | assimilated works expressed by a process analogous to cinematography;
74 | a work of drawing, painting, architecture, sculpture, engraving or
75 | lithography; a photographic work to which are assimilated works
76 | expressed by a process analogous to photography; a work of applied
77 | art; an illustration, map, plan, sketch or three-dimensional work
78 | relative to geography, topography, architecture or science; a
79 | performance; a broadcast; a phonogram; a compilation of data to the
80 | extent it is protected as a copyrightable work; or a work performed by
81 | a variety or circus performer to the extent it is not otherwise
82 | considered a literary or artistic work.
83 | g. "You" means an individual or entity exercising rights under this
84 | License who has not previously violated the terms of this License with
85 | respect to the Work, or who has received express permission from the
86 | Licensor to exercise rights under this License despite a previous
87 | violation.
88 | h. "Publicly Perform" means to perform public recitations of the Work and
89 | to communicate to the public those public recitations, by any means or
90 | process, including by wire or wireless means or public digital
91 | performances; to make available to the public Works in such a way that
92 | members of the public may access these Works from a place and at a
93 | place individually chosen by them; to perform the Work to the public
94 | by any means or process and the communication to the public of the
95 | performances of the Work, including by public digital performance; to
96 | broadcast and rebroadcast the Work by any means including signs,
97 | sounds or images.
98 | i. "Reproduce" means to make copies of the Work by any means including
99 | without limitation by sound or visual recordings and the right of
100 | fixation and reproducing fixations of the Work, including storage of a
101 | protected performance or phonogram in digital form or other electronic
102 | medium.
103 |
104 | 2. Fair Dealing Rights. Nothing in this License is intended to reduce,
105 | limit, or restrict any uses free from copyright or rights arising from
106 | limitations or exceptions that are provided for in connection with the
107 | copyright protection under copyright law or other applicable laws.
108 |
109 | 3. License Grant. Subject to the terms and conditions of this License,
110 | Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
111 | perpetual (for the duration of the applicable copyright) license to
112 | exercise the rights in the Work as stated below:
113 |
114 | a. to Reproduce the Work, to incorporate the Work into one or more
115 | Collections, and to Reproduce the Work as incorporated in the
116 | Collections;
117 | b. to create and Reproduce Adaptations provided that any such Adaptation,
118 | including any translation in any medium, takes reasonable steps to
119 | clearly label, demarcate or otherwise identify that changes were made
120 | to the original Work. For example, a translation could be marked "The
121 | original work was translated from English to Spanish," or a
122 | modification could indicate "The original work has been modified.";
123 | c. to Distribute and Publicly Perform the Work including as incorporated
124 | in Collections; and,
125 | d. to Distribute and Publicly Perform Adaptations.
126 | e. For the avoidance of doubt:
127 |
128 | i. Non-waivable Compulsory License Schemes. In those jurisdictions in
129 | which the right to collect royalties through any statutory or
130 | compulsory licensing scheme cannot be waived, the Licensor
131 | reserves the exclusive right to collect such royalties for any
132 | exercise by You of the rights granted under this License;
133 | ii. Waivable Compulsory License Schemes. In those jurisdictions in
134 | which the right to collect royalties through any statutory or
135 | compulsory licensing scheme can be waived, the Licensor waives the
136 | exclusive right to collect such royalties for any exercise by You
137 | of the rights granted under this License; and,
138 | iii. Voluntary License Schemes. The Licensor waives the right to
139 | collect royalties, whether individually or, in the event that the
140 | Licensor is a member of a collecting society that administers
141 | voluntary licensing schemes, via that society, from any exercise
142 | by You of the rights granted under this License.
143 |
144 | The above rights may be exercised in all media and formats whether now
145 | known or hereafter devised. The above rights include the right to make
146 | such modifications as are technically necessary to exercise the rights in
147 | other media and formats. Subject to Section 8(f), all rights not expressly
148 | granted by Licensor are hereby reserved.
149 |
150 | 4. Restrictions. The license granted in Section 3 above is expressly made
151 | subject to and limited by the following restrictions:
152 |
153 | a. You may Distribute or Publicly Perform the Work only under the terms
154 | of this License. You must include a copy of, or the Uniform Resource
155 | Identifier (URI) for, this License with every copy of the Work You
156 | Distribute or Publicly Perform. You may not offer or impose any terms
157 | on the Work that restrict the terms of this License or the ability of
158 | the recipient of the Work to exercise the rights granted to that
159 | recipient under the terms of the License. You may not sublicense the
160 | Work. You must keep intact all notices that refer to this License and
161 | to the disclaimer of warranties with every copy of the Work You
162 | Distribute or Publicly Perform. When You Distribute or Publicly
163 | Perform the Work, You may not impose any effective technological
164 | measures on the Work that restrict the ability of a recipient of the
165 | Work from You to exercise the rights granted to that recipient under
166 | the terms of the License. This Section 4(a) applies to the Work as
167 | incorporated in a Collection, but this does not require the Collection
168 | apart from the Work itself to be made subject to the terms of this
169 | License. If You create a Collection, upon notice from any Licensor You
170 | must, to the extent practicable, remove from the Collection any credit
171 | as required by Section 4(b), as requested. If You create an
172 | Adaptation, upon notice from any Licensor You must, to the extent
173 | practicable, remove from the Adaptation any credit as required by
174 | Section 4(b), as requested.
175 | b. If You Distribute, or Publicly Perform the Work or any Adaptations or
176 | Collections, You must, unless a request has been made pursuant to
177 | Section 4(a), keep intact all copyright notices for the Work and
178 | provide, reasonable to the medium or means You are utilizing: (i) the
179 | name of the Original Author (or pseudonym, if applicable) if supplied,
180 | and/or if the Original Author and/or Licensor designate another party
181 | or parties (e.g., a sponsor institute, publishing entity, journal) for
182 | attribution ("Attribution Parties") in Licensor's copyright notice,
183 | terms of service or by other reasonable means, the name of such party
184 | or parties; (ii) the title of the Work if supplied; (iii) to the
185 | extent reasonably practicable, the URI, if any, that Licensor
186 | specifies to be associated with the Work, unless such URI does not
187 | refer to the copyright notice or licensing information for the Work;
188 | and (iv) , consistent with Section 3(b), in the case of an Adaptation,
189 | a credit identifying the use of the Work in the Adaptation (e.g.,
190 | "French translation of the Work by Original Author," or "Screenplay
191 | based on original Work by Original Author"). The credit required by
192 | this Section 4 (b) may be implemented in any reasonable manner;
193 | provided, however, that in the case of a Adaptation or Collection, at
194 | a minimum such credit will appear, if a credit for all contributing
195 | authors of the Adaptation or Collection appears, then as part of these
196 | credits and in a manner at least as prominent as the credits for the
197 | other contributing authors. For the avoidance of doubt, You may only
198 | use the credit required by this Section for the purpose of attribution
199 | in the manner set out above and, by exercising Your rights under this
200 | License, You may not implicitly or explicitly assert or imply any
201 | connection with, sponsorship or endorsement by the Original Author,
202 | Licensor and/or Attribution Parties, as appropriate, of You or Your
203 | use of the Work, without the separate, express prior written
204 | permission of the Original Author, Licensor and/or Attribution
205 | Parties.
206 | c. Except as otherwise agreed in writing by the Licensor or as may be
207 | otherwise permitted by applicable law, if You Reproduce, Distribute or
208 | Publicly Perform the Work either by itself or as part of any
209 | Adaptations or Collections, You must not distort, mutilate, modify or
210 | take other derogatory action in relation to the Work which would be
211 | prejudicial to the Original Author's honor or reputation. Licensor
212 | agrees that in those jurisdictions (e.g. Japan), in which any exercise
213 | of the right granted in Section 3(b) of this License (the right to
214 | make Adaptations) would be deemed to be a distortion, mutilation,
215 | modification or other derogatory action prejudicial to the Original
216 | Author's honor and reputation, the Licensor will waive or not assert,
217 | as appropriate, this Section, to the fullest extent permitted by the
218 | applicable national law, to enable You to reasonably exercise Your
219 | right under Section 3(b) of this License (right to make Adaptations)
220 | but not otherwise.
221 |
222 | 5. Representations, Warranties and Disclaimer
223 |
224 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
225 | OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
226 | KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
227 | INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
228 | FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
229 | LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
230 | WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
231 | OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
232 |
233 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
234 | LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
235 | ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
236 | ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
237 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
238 |
239 | 7. Termination
240 |
241 | a. This License and the rights granted hereunder will terminate
242 | automatically upon any breach by You of the terms of this License.
243 | Individuals or entities who have received Adaptations or Collections
244 | from You under this License, however, will not have their licenses
245 | terminated provided such individuals or entities remain in full
246 | compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
247 | survive any termination of this License.
248 | b. Subject to the above terms and conditions, the license granted here is
249 | perpetual (for the duration of the applicable copyright in the Work).
250 | Notwithstanding the above, Licensor reserves the right to release the
251 | Work under different license terms or to stop distributing the Work at
252 | any time; provided, however that any such election will not serve to
253 | withdraw this License (or any other license that has been, or is
254 | required to be, granted under the terms of this License), and this
255 | License will continue in full force and effect unless terminated as
256 | stated above.
257 |
258 | 8. Miscellaneous
259 |
260 | a. Each time You Distribute or Publicly Perform the Work or a Collection,
261 | the Licensor offers to the recipient a license to the Work on the same
262 | terms and conditions as the license granted to You under this License.
263 | b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
264 | offers to the recipient a license to the original Work on the same
265 | terms and conditions as the license granted to You under this License.
266 | c. If any provision of this License is invalid or unenforceable under
267 | applicable law, it shall not affect the validity or enforceability of
268 | the remainder of the terms of this License, and without further action
269 | by the parties to this agreement, such provision shall be reformed to
270 | the minimum extent necessary to make such provision valid and
271 | enforceable.
272 | d. No term or provision of this License shall be deemed waived and no
273 | breach consented to unless such waiver or consent shall be in writing
274 | and signed by the party to be charged with such waiver or consent.
275 | e. This License constitutes the entire agreement between the parties with
276 | respect to the Work licensed here. There are no understandings,
277 | agreements or representations with respect to the Work not specified
278 | here. Licensor shall not be bound by any additional provisions that
279 | may appear in any communication from You. This License may not be
280 | modified without the mutual written agreement of the Licensor and You.
281 | f. The rights granted under, and the subject matter referenced, in this
282 | License were drafted utilizing the terminology of the Berne Convention
283 | for the Protection of Literary and Artistic Works (as amended on
284 | September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
285 | Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
286 | and the Universal Copyright Convention (as revised on July 24, 1971).
287 | These rights and subject matter take effect in the relevant
288 | jurisdiction in which the License terms are sought to be enforced
289 | according to the corresponding provisions of the implementation of
290 | those treaty provisions in the applicable national law. If the
291 | standard suite of rights granted under applicable copyright law
292 | includes additional rights not granted under this License, such
293 | additional rights are deemed to be included in the License; this
294 | License is not intended to restrict the license of any rights under
295 | applicable law.
296 |
297 |
298 | Creative Commons Notice
299 |
300 | Creative Commons is not a party to this License, and makes no warranty
301 | whatsoever in connection with the Work. Creative Commons will not be
302 | liable to You or any party on any legal theory for any damages
303 | whatsoever, including without limitation any general, special,
304 | incidental or consequential damages arising in connection to this
305 | license. Notwithstanding the foregoing two (2) sentences, if Creative
306 | Commons has expressly identified itself as the Licensor hereunder, it
307 | shall have all rights and obligations of Licensor.
308 |
309 | Except for the limited purpose of indicating to the public that the
310 | Work is licensed under the CCPL, Creative Commons does not authorize
311 | the use by either party of the trademark "Creative Commons" or any
312 | related trademark or logo of Creative Commons without the prior
313 | written consent of Creative Commons. Any permitted use will be in
314 | compliance with Creative Commons' then-current trademark usage
315 | guidelines, as may be published on its website or otherwise made
316 | available upon request from time to time. For the avoidance of doubt,
317 | this trademark restriction does not form part of this License.
318 |
319 | Creative Commons may be contacted at http://creativecommons.org/.
320 |
--------------------------------------------------------------------------------