├── README.md └── enex-dump.php /README.md: -------------------------------------------------------------------------------- 1 | enex-dump 2 | ========= 3 | 4 | PHP script that accepts an Evernote export (ENEX) file and produces a folder of plain text documents. 5 | 6 | Please see comment at top of script for configuration and usage instructions. 7 | 8 | Note about non-breaking spaces 9 | ------------------------------ 10 | 11 | I've found out the hard way that ENEX exports often contain non-breaking space characters (0xA0) that you may not notice right away because they look like regular spaces. This script does not remove them, so be aware that they might exist. 12 | -------------------------------------------------------------------------------- /enex-dump.php: -------------------------------------------------------------------------------- 1 | 5 | // 6 | // This script takes an Evernote export (ENEX) file as input 7 | // and exports each individual note as a plain-text file in the 8 | // specified output folder. 9 | // 10 | // All HTML formatting and attachments are stripped out. 11 | // 12 | // The output files are named after the title of the note. 13 | // 14 | // The title of the note is also included as the first line of 15 | // the exported file. 16 | // 17 | // Script will attempt to create the output folder if it doesn't exist. 18 | // 19 | // Configure the variables below before running. Default paths are 20 | // relative to current directory. 21 | // 22 | // Invoke like so: 23 | // 24 | // php enex-dump.php 25 | // 26 | // By default, we look for an input file named "My Notes.enex", 27 | // but you can supply an additional parameter to override this: 28 | // 29 | // php enex-dump.php allnotes.enex 30 | // 31 | 32 | if ( $argc > 1 ) 33 | { 34 | $file = $argv[1]; 35 | } 36 | else 37 | { 38 | $file = "My Notes.enex"; // Path of default input file 39 | } 40 | 41 | $outdir = "output"; // Path of output folder 42 | $ext = "txt"; // Extension to use for exported notes 43 | 44 | // 45 | 46 | $pos = 0; 47 | $nodes = array(); 48 | 49 | @mkdir($outdir); 50 | 51 | if ( !($fp = fopen($file, "r")) ) 52 | { 53 | die("could not open XML input"); 54 | } 55 | 56 | while ( $getline = fread($fp, 4096) ) 57 | { 58 | $data = $data . $getline; 59 | } 60 | 61 | $count = 0; 62 | $pos = 0; 63 | 64 | while ( $node = getElementByName($data, "", "") ) 65 | { 66 | $nodes[$count] = $node; 67 | $count++; 68 | $data = substr($data, $pos); 69 | } 70 | 71 | for ( $i = 0; $i < $count; $i++) 72 | { 73 | $title = cleanup(getElementByName($nodes[$i], "", "")); 74 | $content = cleanup(getElementByName($nodes[$i], "", "")); 75 | 76 | // Obtain note creation timestamp 77 | $timestamp = cleanup(getElementByName($nodes[$i], "", "")); 78 | 79 | // sanitize the / in titles for filenames 80 | 81 | $outfile = sprintf('%s/%s.%s', $outdir, str_replace('/', '-', $title), $ext); 82 | 83 | // echo the filename 84 | 85 | echo $outfile . PHP_EOL; 86 | 87 | file_put_contents($outfile, $title . "\n\n" . $content); 88 | touch($outfile, strtotime($timestamp)); // Change output file timestamp to match note creation timestamp 89 | } 90 | 91 | exit; 92 | 93 | 94 | function getElementByName($xml, $start, $end) 95 | { 96 | global $pos; 97 | 98 | $startpos = strpos($xml, $start); 99 | 100 | if ( $startpos === false ) 101 | { 102 | return false; 103 | } 104 | 105 | $endpos = strpos($xml, $end); 106 | $endpos = $endpos + strlen($end); 107 | $pos = $endpos; 108 | $endpos = $endpos - $startpos; 109 | $endpos = $endpos - strlen($end); 110 | $tag = substr($xml, $startpos, $endpos); 111 | $tag = substr($tag, strlen($start)); 112 | 113 | return $tag; 114 | } 115 | 116 | function cleanup($str) 117 | { 118 | $str = strip_tags($str); 119 | $str = preg_replace('/\]\]>$/', '', $str); 120 | $str = trim($str); 121 | $str = html_entity_decode($str); 122 | 123 | return $str; 124 | } 125 | 126 | --------------------------------------------------------------------------------